微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用可变参数调用函数,其中可变参数是引用

如何解决使用可变参数调用函数,其中可变参数是引用

我尝试实现一个类,该类接受一个函数一个可变参数列表作为输入,以便稍后在工作线程上执行这些函数。我当前的实现有问题,如果其中一个参数是引用。

看看以下较小的代码示例:

#include <functional>
#include <iostream>

template<typename Result,typename ...Args>
Result Foo(Result f(Args...),Args... args)
{
    return f(args...);
}

int BarValue(int x){return x;}
int BarPointer(int* x){ *x++;return *x; }
int BarRef(int& x){ x++; return x; }

int main()
{
    int x{0};
    std::cout << Foo(BarValue,x)           << std::endl;
    std::cout << Foo(BarPointer,&x)        << std::endl;
    std::cout << Foo(BarRef,x)             << std::endl; // does not compile: Error 1
    std::cout << Foo(BarRef,std::ref(x))   << std::endl; // does also not compile: Error 2
    return 0;
}

错误 1:

<source>: In function 'int main()':
<source>:31:31: error: no matching function for call to 'Foo(int (&)(int&),int&)'
   31 |     std::cout << Foo(BarRef,x)             << std::endl;
      |                               ^
<source>:4:8: note: candidate: 'template<class Result,class ... Args> Result Foo(Result (*)(Args ...),Args ...)'
    4 | Result Foo(Result f(Args...),Args... args)
      |        ^~~
<source>:4:8: note:   template argument deduction/substitution Failed:
<source>:31:31: note:   inconsistent parameter pack deduction with 'int&' and 'int'
   31 |     std::cout << Foo(BarRef,x)             << std::endl;
      |                               ^
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:31:31: error: no matching function for call to 'Foo(int (&)(int&),x)             << std::endl;
      |  

                         ^

错误 2:

<source>: In function 'int main()':
<source>:33:41: error: no matching function for call to 'Foo(int (&)(int&),std::reference_wrapper<int>)'
   33 |     std::cout << Foo(BarRef,std::ref(x))   << std::endl;
      |                                         ^
<source>:5:8: note: candidate: 'template<class Result,Args ...)'
    5 | Result Foo(Result f(Args...),Args... args)
      |        ^~~
<source>:5:8: note:   template argument deduction/substitution Failed:
<source>:33:41: note:   inconsistent parameter pack deduction with 'int&' and 'std::reference_wrapper<int>'
   33 |     std::cout << Foo(BarRef,std::ref(x))   << std::endl;
      |                                         ^
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:33:41: error: no matching function for call to 'Foo(int (&)(int&),std::ref(x))   << std::endl;
      |                                         ^
Execution build compiler returned: 1

使用 gcc 10.2 和 -O3 -std=c++17 编译:GodBolt

我该如何解决这个参考问题?

解决方法

我的建议是,您可以查看标准库本身如何使用模板来传递可调用对象(函数、lambda 等):通过使用单一模板类型:

template<typename Func,typename ...Args>
auto Foo(Func f,Args&&... args)
{
    return f(std::forward<Args>(args)...);
}

请注意,我添加了对 std::forward 的调用以正确“转发”参数。

另请注意,我制作了返回类型 auto 以让编译器推断返回类型。


如果我正确理解您的评论,您想创建一个变量来保存 f 的返回值,然后稍后返回该变量吗?然后,您可以像在编译器-资源管理器链接中那样使用 decltype 执行此操作,也可以在定义和初始化变量时再次使用普通的 auto

template<typename Func,Args&&... args)
{
    auto value = f(std::forward<Args>(args)...);

    // Do something with the variable value...

    return value;
}

如果函数 f 具有 void 返回值,这当然不起作用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。