将lambda的非空返回类型强制转换为函数指针

问题描述 投票:0回答:1

我正在尝试将lambda函数强制转换为函数指针。但是,当lambda具有非空返回类型时,强制转换失败。详细信息请参见代码段。

是否可以将fun2转换为通用函数指针,可以保存以供以后使用?

更新:我的意图是将各种函数转换为可保存在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++ lambda function-pointers
1个回答
1
投票

问题是您正在使用C风格的显式强制转换。这些都是非常危险的。

在这种情况下,问题是fun3(与fun2相反)已经衰减到类型为int(*)()的函数指针。

然后将其转换为void(*)()。之所以可行,是因为C样式强制转换将尝试执行不同的C ++强制转换表达式,直到一个有效为止。特别是,它还将尝试reinterpret_cast

reinterpret_cast<voidFunctionType>(fun3)

有效,因为reinterpret_cast可以将any函数指针转换为any其他函数指针。

但是,不允许您通过获取的指针来调用该函数。这样做会使您的程序具有undefined behavior。如您所见,此演员表的用途非常有限,如果您不了解它,将会很危险。

不要使用C样式强制转换,而应使用static_cast<voidFunctionType>(fun3),在两种情况下,您都将获得适当的编译时错误。

您不能使用返回一种类型的函数(无论是自由函数还是lambda),就好像它返回了另一种(或没有)类型一样。因此,将返回int的lambda转换为void(*)()没有任何意义。


如果您确实要保存任意函数指针,则可以通过首先将其转换为函数指针,然后使用reinterpret_cast将其强制转换为目标函数指针类型来使lambda转换起作用。我仍然不会使用C样式转换,因为reinterpret_cast至少会清楚表明您打算进行哪种转换:

auto casted_fun2 = reinterpret_cast<voidFunctionType>(+fun2);

一元+是强制lambda进行函数指针转换的常见技巧。

如上所述,您必须在调用指针之前将其强制转换回其原始类型,因此您需要将类型信息存储在某个地方。我不确定您打算怎么做,但是您可能需要实现std::function的某些扩展版本,例如this question了解std::function的操作方式。

© www.soinside.com 2019 - 2024. All rights reserved.