使用可变参数调用函数,其中可变参数是引用
Call function with variadic arguments where variadic arugments are references
我尝试实现一个 class,它接受一个函数和一个可变参数列表作为输入,以便稍后在工作线程上执行这些函数。如果参数之一是引用,我当前的实现有问题。
查看以下较小的代码示例:
#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&), 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;
|
^
错误 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, class ... Args> Result Foo(Result (*)(Args ...), 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::reference_wrapper<int>)'
33 | std::cout << Foo(BarRef, std::ref(x)) << std::endl;
| ^
<source>:5:8: note: candidate: 'template<class Result, class ... Args> Result Foo(Result (*)(Args ...), 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;
| ^
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
的调用以正确“转发”参数。
另请注意,我制作 return 类型 auto
是为了让编译器推断出 return 类型。
如果我对你的评论理解正确,你想创建一个变量来保存 f
的 returned 值,然后再 return 该变量?然后,您可以像在编译器资源管理器 link 中那样使用 decltype
来完成它,或者在定义和初始化变量时再次使用纯 auto
:
template<typename Func, typename ...Args>
auto Foo(Func f, Args&&... args)
{
auto value = f(std::forward<Args>(args)...);
// Do something with the variable value...
return value;
}
如果函数 f
具有 void
return 值,这当然不起作用。
我尝试实现一个 class,它接受一个函数和一个可变参数列表作为输入,以便稍后在工作线程上执行这些函数。如果参数之一是引用,我当前的实现有问题。
查看以下较小的代码示例:
#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&), 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;
|
^
错误 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, class ... Args> Result Foo(Result (*)(Args ...), 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::reference_wrapper<int>)'
33 | std::cout << Foo(BarRef, std::ref(x)) << std::endl;
| ^
<source>:5:8: note: candidate: 'template<class Result, class ... Args> Result Foo(Result (*)(Args ...), 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;
| ^
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
的调用以正确“转发”参数。
另请注意,我制作 return 类型 auto
是为了让编译器推断出 return 类型。
如果我对你的评论理解正确,你想创建一个变量来保存 f
的 returned 值,然后再 return 该变量?然后,您可以像在编译器资源管理器 link 中那样使用 decltype
来完成它,或者在定义和初始化变量时再次使用纯 auto
:
template<typename Func, typename ...Args>
auto Foo(Func f, Args&&... args)
{
auto value = f(std::forward<Args>(args)...);
// Do something with the variable value...
return value;
}
如果函数 f
具有 void
return 值,这当然不起作用。