I have a macro:
#define WRAP_FUNCTION(wrapper_name, function, ret_type, arg1_type, arg2_type, ...)
And I would like it to define a function like this:
ret_type wrapper_name(arg1_type arg1, arg2_type arg2, ...) {
return function(arg1, arg2, ...)
}
Except where the ellipses (along with arg1 and arg2) are a dynamically sized list. I could create the function prototype using __VA_ARGS__
, but that doesn't give me names for the arguments to pass to the wrapped function.
I assume the usual approach would be std::apply
(or to copy-paste the implementation of std::apply
, since it's not available in C++11). Unfortunately the argument function
may be overloaded or a compiler built-in so it cannot reliably be passed as a function type.
What I have right now is the generation of a variadic template function:
template<class... Args>
ret_type wrapper_name(Args... args) {
return function(std::forward<Args>(args)...);
}
But this causes a world of problems with conversions because there's a lot that cannot be done with implicit conversions in this form when the wrapped function is overloaded. It also can't wrap function-like macros, but I think addressing that problem may be impossible anyway.
Update: With a bit of fiddling I can make the wrapper function enforce its argument types this way:
#define WRAPPER(name, ret_type, function, ...) \
template<class... Args> struct name##_impl { static inline \
ret_type func(Args... args) { return function(std::forward<Args>(args)...); } }; \
template<class... Args> ret_type name(Args... args) \
{ return name##_impl<__VA_ARGS__>::func(std::forward<Args>(args)...); }
Unfortunately, this leaves me with the problem that I cannot overload the identifier name
with different argument lists. My attempts at making the name
template a specialisation have resulted in a lot of complaints either about partial specialisation of a function or about not forwarding any template arguments to the generic template.
Using a variadic macro to generate a non-template wrapper, you can use some macro tricks, specifically this trick, to generate your argument list with names so you can call your target function, eg:
// this example supports functions that have 0..3 arguments,
// you can expand this for more arguments if needed...
#define _ARG_PARAMS3(type1, type2, type3) type1 arg1, type2 arg2, type3 arg3
#define _ARG_NAMES3(type1, type2, type3) arg1, arg2, arg3
#define _ARG_PARAMS2(type1, type2) type1 arg1, type2 arg2
#define _ARG_NAMES2(type1, type2) arg1, arg2
#define _ARG_PARAMS1(type1) type1 arg1
#define _ARG_NAMES1(type1) arg1
#define _ARG_PARAMS0()
#define _ARG_NAMES0()
#define _GET_OVERRIDE(_1, _2, _3, _4, NAME, ...) NAME
#define ARG_PARAMS(...) _GET_OVERRIDE("ignored", __VA_ARGS__ __VA_OPT__(,) \
_ARG_PARAMS3, _ARG_PARAMS2, _ARG_PARAMS1, _ARG_PARAMS0)(__VA_ARGS__)
#define ARG_NAMES(...) _GET_OVERRIDE("ignored", __VA_ARGS__ __VA_OPT__(,) \
_ARG_NAMES3, _ARG_NAMES2, _ARG_NAMES1, _ARG_NAMES0)(__VA_ARGS__)
#define WRAP_FUNCTION(wrapper_name, function, ret_type, ...) \
ret_type wrapper_name(ARG_PARAMS(__VA_ARGS__)) { \
return function(ARG_NAMES(__VA_ARGS__)); \
}
And then you can use WRAP_FUNCTION
like you want:
int funcWith3Args(int arg1, int arg2, int arg3)
{
...
}
string funcWithNoArgs()
{
...
}
WRAP_FUNCTION(wrapper3Args, funcWith3Args, int, int, int, int)
WRAP_FUNCTION(wrapperNoArgs, funcWithNoArgs, string)
...
wrapper3Args(1, 2, 3);
wrapperNoArgs();
...
With some tweaking, I'm sure you can also generate a template wrapper, too.