将带有可变参数的模板函数分配给函数指针

问题描述

在 C++ 中,我试图制作采用第一个参数并在其上调用方法的转发包装器。 这在给定代码中的 wrapper 方法中结束。这在调用时工作正常。

但是我想将此模板化包装器分配给函数指针。在我的用例中,函数指针是给定的,我不能将其更改为 std::function 或类似的东西。这是因为它在一个C api中使用的地方。

我确实创建了以下示例:

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

方法调用工作正常,但是:

    int (*serialize)(void* handle,int j);
    serialize = wrapper<&MyTestClass::method1,MyTestClass>;

不起作用,给我错误

/.../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) {
             ^~~~~~~

经过一些尝试后,我确实发现 Params&& ... args 部分导致了问题,因为如果我制作了一个没有可变参数的更明确的包装器,那么它确实有效。

我的主要问题是:我是否可以将带有可变参数的模板化方法分配给函数指针,以及如何分配?

解决方法

问题是 wrapperargs 作为转发引用,它的类型总是引用:lvalue-reference 或 rvalue-reference。但是 serialize 被声明为函数指针,采用 ij 类型为 int 的按值,它们不能匹配引用类型,这使得 {{ 上的模板参数推导1}} 在 Params 中失败。

您可以通过更改 serialize = wrapper<&MyTestClass::method1,MyTestClass>; 声明中的 ij 类型来修复它。

例如

serialize

LIVE Clang LIVE Gcc

或者更改 int (*serialize)(void* handle,int&& i,int&& j); serialize = wrapper<&MyTestClass::method1,MyTestClass>; wrapper 的值。

例如

args

LIVE Clang LIVE Gcc