【问题标题】:Assignen a template function with Variadic arguments to a function pointer将带有可变参数的模板函数分配给函数指针
【发布时间】:2021-05-28 08:28:55
【问题描述】:

在 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 i, 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&amp;&amp; ... args 部分导致了问题,因为如果我制作一个没有可变参数的更明确的包装器,那么它确实有效。

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

【问题讨论】:

  • C++中没有“模板函数”,有函数模板。

标签: c++ templates function-pointers


【解决方案1】:

问题是wrapperargs 作为转发引用,它的类型总是引用:左值引用或右值引用。但是serialize 被声明为函数指针,采用ij 类型为int 的值,它们不能匹配引用类型,这使得Params 上的模板参数推导在serialize = wrapper&lt;&amp;MyTestClass::method1, MyTestClass&gt;; 中失败。

您可以通过在serialize 的声明中更改ij 的类型来修复它。

例如

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

LIVE ClangLIVE Gcc

或按值更改wrapper 采用args

例如

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

LIVE ClangLIVE Gcc

【讨论】:

  • OP声明serialize用于与C API交互。
  • 我认为这不是正确的答案,但这段代码在 g++ 上仍会失败,我认为 && 由于引用崩溃而不是问题。
  • @N0ll_Boy 哪个不使用 g++ 编译?引用折叠后,类型将为int&amp;int&amp;&amp;,它们与int 不匹配。
  • @songyuanyao 应该是const int &amp; 而不是int &amp;&amp; ??
  • 在我的情况下,从 wrapper 方法中的参数中删除 &amp;&amp; 解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 2017-02-24
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 2015-01-20
  • 1970-01-01
相关资源
最近更新 更多