将具有非空 return 类型的 lambda 转换为函数指针
Casting lambda with non-void return type to function pointer
我正在尝试将 lambda 函数 转换为 函数指针。但是,当 lambda 具有非空 return 类型时,转换会失败。详情见代码片段。
是否可以将 fun2
转换为 通用函数指针,我可以将其保存以备后用?
更新:我的目的是将各种函数转换为 "generic function pointer",可以保存在 std::map
中。使用后,我会将其转换回其原始函数类型。
#include <iostream>
int fun3() { return 1; }
int main(int argc, char *argv[]) {
typedef void (*voidFunctionType)(void);
// Case 1: lambda, return type void
auto fun1 = []() { std::cout << "hello" << std::endl; };
// -> compiles
auto casted_fun1 = (voidFunctionType)fun1;
// Case 2: lambda, return type int
auto fun2 = []() { std::cout << "world" << std::endl; return -1;};
// -> error: invalid cast from type ‘main(int, char**)::<lambda()>’ to type ‘voidFunctionType {aka void (*)()}’
auto casted_fun2 = (voidFunctionType)fun2;
// Case 3: free function, return type int -> compiles
auto casted_fun3 = (voidFunctionType)fun3;
return 0;
}
问题是您使用的是 C 风格的显式转换。这些都是出了名的危险。
在这种情况下,问题是 fun3
(与 fun2
形成对比)已经衰减为 int(*)()
.
类型的函数指针
然后您将其转换为 void(*)()
。这是有效的,因为 C 风格的强制转换将尝试执行不同的 C++ 强制转换表达式,直到一个有效。特别是它还会尝试 reinterpret_cast
.
reinterpret_cast<voidFunctionType>(fun3)
有效,因为 reinterpret_cast
可以将 any 函数指针转换为 any 其他函数指针。
但是,不允许通过获取的指针调用函数。这样做会导致您的程序出现 未定义的行为 。如您所见,此转换的用途非常有限,如果您不注意它,它会很危险。
不要使用 C 风格的转换,而是使用 static_cast<voidFunctionType>(fun3)
,在这两种情况下您都会得到相应的编译时错误。
您不能使用 returns 一种类型的函数(无论是自由函数还是 lambda),就像它返回另一种(或没有)类型一样。因此,将 returns int
的 lambda 转换为 void(*)()
没有意义。
如果你真的想保存任意函数指针,你可以先将lambda转换为函数指针,然后然后使用 reinterpret_cast
将其转换为目标函数指针类型。我仍然不会使用 C 风格的转换,因为 reinterpret_cast
至少会清楚地表明你打算做什么样的转换:
auto casted_fun2 = reinterpret_cast<voidFunctionType>(+fun2);
一元 +
是强制将 lambda 转换为函数指针的常用技巧。但还要注意,只有没有捕获的 lambda 可以转换为函数指针。
正如我上面所解释的,您 必须 在调用它之前将指针转换回其原始类型,因此您需要将类型信息存储在某处。我不确定你打算怎么做,但你可能需要实现 std::function
的一些扩展版本,参见例如this question std::function
是如何做到的。
我正在尝试将 lambda 函数 转换为 函数指针。但是,当 lambda 具有非空 return 类型时,转换会失败。详情见代码片段。
是否可以将 fun2
转换为 通用函数指针,我可以将其保存以备后用?
更新:我的目的是将各种函数转换为 "generic function pointer",可以保存在 std::map
中。使用后,我会将其转换回其原始函数类型。
#include <iostream>
int fun3() { return 1; }
int main(int argc, char *argv[]) {
typedef void (*voidFunctionType)(void);
// Case 1: lambda, return type void
auto fun1 = []() { std::cout << "hello" << std::endl; };
// -> compiles
auto casted_fun1 = (voidFunctionType)fun1;
// Case 2: lambda, return type int
auto fun2 = []() { std::cout << "world" << std::endl; return -1;};
// -> error: invalid cast from type ‘main(int, char**)::<lambda()>’ to type ‘voidFunctionType {aka void (*)()}’
auto casted_fun2 = (voidFunctionType)fun2;
// Case 3: free function, return type int -> compiles
auto casted_fun3 = (voidFunctionType)fun3;
return 0;
}
问题是您使用的是 C 风格的显式转换。这些都是出了名的危险。
在这种情况下,问题是 fun3
(与 fun2
形成对比)已经衰减为 int(*)()
.
然后您将其转换为 void(*)()
。这是有效的,因为 C 风格的强制转换将尝试执行不同的 C++ 强制转换表达式,直到一个有效。特别是它还会尝试 reinterpret_cast
.
reinterpret_cast<voidFunctionType>(fun3)
有效,因为 reinterpret_cast
可以将 any 函数指针转换为 any 其他函数指针。
但是,不允许通过获取的指针调用函数。这样做会导致您的程序出现 未定义的行为 。如您所见,此转换的用途非常有限,如果您不注意它,它会很危险。
不要使用 C 风格的转换,而是使用 static_cast<voidFunctionType>(fun3)
,在这两种情况下您都会得到相应的编译时错误。
您不能使用 returns 一种类型的函数(无论是自由函数还是 lambda),就像它返回另一种(或没有)类型一样。因此,将 returns int
的 lambda 转换为 void(*)()
没有意义。
如果你真的想保存任意函数指针,你可以先将lambda转换为函数指针,然后然后使用 reinterpret_cast
将其转换为目标函数指针类型。我仍然不会使用 C 风格的转换,因为 reinterpret_cast
至少会清楚地表明你打算做什么样的转换:
auto casted_fun2 = reinterpret_cast<voidFunctionType>(+fun2);
一元 +
是强制将 lambda 转换为函数指针的常用技巧。但还要注意,只有没有捕获的 lambda 可以转换为函数指针。
正如我上面所解释的,您 必须 在调用它之前将指针转换回其原始类型,因此您需要将类型信息存储在某处。我不确定你打算怎么做,但你可能需要实现 std::function
的一些扩展版本,参见例如this question std::function
是如何做到的。