1

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?

1
  • There are no "template functions" in C++, there are function templates. Commented May 28, 2021 at 8:29

1 Answer 1

1

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>;

LIVE Clang LIVE Gcc

Or change wrapper taking args by-value.

E.g.

template<auto FUNC, typename T, typename ... Params>
static auto wrapper(void* handle, Params ... args)

LIVE Clang LIVE Gcc

Sign up to request clarification or add additional context in comments.

5 Comments

OP stated that serialize is used to interact with C API.
i dont think it's right answer still this code will fail on g++, another thing that i think && is not an problem due to reference collapse.
@N0ll_Boy Which one doesn't compile with g++? After reference collapse the type would be int& or int&&, they don't match int.
@songyuanyao should it be const int & instead of int && ??
In my case removing the && from parameter in the wrapper method solved my issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.