I have some 3rdParty library with a method like this:
bool Invoke(const char* method, Value* args, size_t nargs)
It takes an array of its inner type (convertible to any primitive c++ types) and arg count as its inner params. In my code, I wrote some generalized helper to avoid manual creation and type convertion for each invoke:
template<class ... Args>
bool WrappedValue::Invoke(const char* method, Args&& ... args)
{
3rdParty::Value values[] =
{
3rdParty::Value(std::forward<Args>(args))...
}
return m_value.Invoke(method, values, sizeof ... (Args));
}
It works just fine, but now I should have 3rdParty code defined in my header files and lib connected directly to my main project.
Is it possible to hide implementation details and usage of this 3rd party library? (Use some kind of pimple idiom or proxy object for 3rdParty::Value ). I know that it's not possible to use virtual template methods in c++ to create a proxy or simply move template implementation to .cpp, so I am totally stuck with this problem.
Will be grateful for any help)
Sure. Simply write the equivalent of std::variant<int, double, char, every, other, primitive, type>
.
Now your Invoke
converts your args
into an array (vector, span, whatever) of those variants.
Then you pass this array of variants to your internal Invoke method.
That internal invoke method then uses the equivalent of std::visit
to generate a 3rdParty::Value
from each of your variants.
Boost provides a boost::variant
which would probably work.
You could also roll this by hand. By narrowly specifying your problem, you'd get away with something simpler than a std::variant
. It would be more than a bit of work, however.
Another approach is this
template<class T> struct tag_t {constexpr tag_t(){}; using type=T;};
template<class T> constexpr tag_t<T> tag{};
template<class T, class F, class ... Args>
bool WrappedValue::Invoke(tag_t<T>, F&& f, const char* method, Args&& ... args)
{
T values[] = {
T(std::forward<Args>(args))...
};
return std::forward<F>(f)(method, values, sizeof...(Args));
}
which is simpler. Here you'd write:
bool r = Invoke( tag<3rdParty::Value>, [&](const char* method, 3rdParty::Value* values, std::size_t count) {
m_value.Invoke( method, values, count );
}, 3.14, 42, "hello world");