考虑以下玩具示例:
#include <iostream>
template <typename T>
void foo(T func, int *i) {
if (i) {
func(*i);
} else {
func();
}
}
int main() {
auto n = new int{2};
foo([](int x) { std::cout << x << std::endl; }, n);
foo([]() { std::cout << "Foo" << std::endl; }, nullptr);
return 0;
}
我想创建一个函数,它接收具有不同签名的lambdas函数,并在其范围内调用它们。如果我不在foo
内调用lambda函数,它编译得很好,但如果我调用它,代码就不会编译。
有没有办法接收具有不同签名的lambdas并在函数中调用它?
答案 0 :(得分:4)
在功能模板中,必须将T
确定为一种特定类型,并在整个实例化过程中保持该类型。
然而,您可以通过使foo
成为可变参数模板,并将参数包传递给传入的lambda来完成您想要的任务:
#include <iostream>
template <typename T, typename ...Args>
void foo(T func, Args... args) {
func(std::forward<Args>(args)...);
}
int main() {
auto n = new int{ 2 };
foo([](int x) { std::cout << x << std::endl; }, n[0]);
foo([]() { std::cout << "Foo" << std::endl; });
foo([](int a, int b) { std::cout << a + b << "\n"; }, 3, 2);
}
这种方式foo
只需要包含一个func
的调用,它在每个实例化中都有一致的类型 - 但是可以从一个实例化到下一个实例化。
在这种情况下,当您传递的函数不接受任何参数时,您不会为参数传递特殊值。如果没有参数,你就不要传递参数。
答案 1 :(得分:1)
在第一种使用以下方法实例化模板函数的情况下:
foo([](int x) { std::cout << x << std::endl; }, n);
编译器创建函数,其中(T func)是一个可调用的函数,因此你不能这样做:
void foo(T func, int *i) {
if (i) {
func(*i);
}
//else
//{
// func(); // Can't call T func with no argument.
//} // Commenting this out will compile.
}
使用以下方法实例化模板函数时
foo([]() { std::cout << "Foo" << std::endl; }, nullptr);
编译器创建函数:
void foo(T func, int *i); // Where T func is a callable taking no arguments
因此,与前面的示例相比,您必须在没有给出参数的情况下调用T func。因此你做不到:
template <typename T>
void foo(T func, int *i)
{
//if (i) {
// func(*i); // Can't call T func with one argument, because
// T func function template has been instantiated
// as T func taking no arguments.
//}
//else
{
func(); // This obviously is fine.
}
}