Jef*_*eff 24 c++ lambda function-pointers language-lawyer c++11
在直观的层面上,有意义的是,需要不携带状态(通过引用或其他方式)的lambda应该可以干净地转换为裸函数指针.但是,我最近惊讶地看到GCC,Clang和MSVC中的以下失败:
int main(int, char *[]) {
void (*fp)() = []{}; // OK
//fp = [=]{}; // XXX - no user defined conversion operator available
//fp = [&]{}; // XXX - same ...
}
Run Code Online (Sandbox Code Playgroud)
C++ 17规范(或至少可见的公共草案版本N4713)在第8.4.5.1节[expr.prim.lambda.closure]的第7项中引用了带有和不带捕获的lambda:
没有lambda-capture的非泛型lambda表达式的闭包类型,其约束(如果有的话)被满足有一个转换函数指向函数,C++语言链接(10.5)具有与闭包类型相同的参数和返回类型函数调用运算符....
但是,查看正式语法,您可以在§8.4.5[expr.prim.lambda]中看到以下内容:
- lambda表达式:
- lambda-introducer复合语句
- ...
- lambda介绍人:
- [ lambda-capture opt ]
- ...
在§8.4.5.2 [expr.prim.lambda.capture]中:
- lambda-capture:
- 捕获的默认
- 捕捉列表
- capture-default,capture-list
- capture-default:
- &
- =
因此,所有编制者实际上都遵守了法律条文令我沮丧......
为什么语言将声明的存在定义为声明中的狭义语法区别,而不是基于主体是否包含对任何非静态/捕获状态的引用?
Sha*_*our 11
允许转换的变化是由国家机构评论发起的.请参阅n3052:将Lambdas转换为功能指针,指的是国家机构评论UK 42:
具有空捕获列表的lambda具有与常规函数类型相同的语义.通过要求这种映射,我们得到一个有效的lambda类型,它具有已知的API,也与现有的操作系统和C库函数兼容.
而决议来自N3052:
解决方案:添加一个新段落:"具有空捕获集的lambda表达式应该可转换为指向函数类型R(P)的指针,其中R是返回类型,P是lambda表达式的参数类型列表." 另外,(a)允许转换为函数引用和(b)允许extern"C"函数指针类型可能是好的.
...
在第5段之后添加一个新段落.此编辑的目的是获取没有lambda-capture的lambda的闭包到函数指针转换.
没有lambda-capture的lambda表达式的闭包类型有一个公共的非虚拟非显式const转换函数,用于指向具有与闭包类型的函数调用操作符相同的参数和返回类型的函数.此转换函数返回的值应为函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果.
这就是我们今天所处的位置.请注意,评论说空捕获列表和我们今天所拥有的内容似乎与评论中的措辞相符.
它看起来像是基于国家机构评论的解决方案,并且被狭隘地应用.