将具有非空 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 是如何做到的。