In C++ I am trying to make forwarding wrapper that takes the first argument and calls a method on it.
This ended up in the wrapper
method in the given code. This works fine when calling it.
However I want to assign this templated wrapper to function pointer. In my use-case the function pointer is a given and I can not change it to a std::function
or something like that. This is because the place where it is used in a C api.
I did create the following example:
#include <iostream>
template<auto FUNC, typename T, typename ... Params>
static auto wrapper(void* handle, Params&& ... args) {
auto* ser = static_cast<T*>(handle);
return (ser->*FUNC)(std::forward<Params>(args)...);
}
class MyTestClass {
public:
int method1(int i, int j) { return i + j; }
float method2(float f) {
return f * 2;
}
};
int main() {
MyTestClass thing{};
int (*serialize)(void* handle, int i, int j);
serialize = wrapper<&MyTestClass::method1, MyTestClass>;
auto callMethod1Result = wrapper<&MyTestClass::method1, MyTestClass>(&thing, 1, 2);
std::cout << "callMethod1Result: " << callMethod1Result << std::endl;
return 0;
}
The calling of the method works fine, however:
int (*serialize)(void* handle, int i, int j);
serialize = wrapper<&MyTestClass::method1, MyTestClass>;
does not work, giving me the error:
/.../temp.cpp:23:17: error: no matches converting function ‘wrapper’ to type ‘int (*)(void*, int, int)’
serialize = wrapper<&MyTestClass::method1, MyTestClass>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/.../temp.cpp:4:13: note: candidate is: ‘template<auto FUNC, class T, class ... Params> auto wrapper(void*, Params&& ...)’
static auto wrapper(void* handle, Params&& ... args) {
^~~~~~~
after some trying I did find out that the Params&& ... args
part is causing the issue, because if I make a more explicit wrapper without variadic argument, then it does work.
My main question is: Can I assign a templated method with variadic argument to a function pointer, and how?
The problem is wrapper
taking args
as forwarding reference, its type would always be reference: lvalue-reference or rvalue-reference. But serialize
is declared as function pointer taking i
and j
by-value with type int
, they can't match reference type, which makes template argument deduction on Params
fails in serialize = wrapper<&MyTestClass::method1, MyTestClass>;
.
You can fix it by changing type of i
and j
in declaration of serialize
.
E.g.
int (*serialize)(void* handle, int&& i, int&& j);
serialize = wrapper<&MyTestClass::method1, MyTestClass>;
Or change wrapper
taking args
by-value.
E.g.
template<auto FUNC, typename T, typename ... Params>
static auto wrapper(void* handle, Params ... args)