一个正面的lambda:'+ {}' – 这是什么巫术?

在堆栈溢出的问题重新定义在C ++ 11不允许的lambdas,为什么? ,一个小程序不能编译:

int main() { auto test = []{}; test = []{}; } 

问题得到解答,一切似乎都很好。 然后来到Johannes Schaub ,做了一个有趣的观察 :

如果你在第一个lambda之前加上+ ,神奇地开始工作。

所以我很好奇:为什么下面的工作?

 int main() { auto test = +[]{}; // Note the unary operator + before the lambda test = []{}; } 

它用GCC 4.7+和Clang 3.2+编译得很好。 代码标准是否符合?

是的,代码是标准符合的。 +触发转换为一个简单的旧的函数指针的lambda。

会发生什么呢?

编译器会看到第一个lambda( []{} ),并根据§5.1.2生成一个闭包对象。 由于lambda是一个非捕获 lambda,适用于:

5.1.2 Lambdaexpression式[expr.prim.lambda]

6不带lambda捕获lambdaexpression式的闭包types有一个公共的非虚拟的非显式const转换函数,指向具有与闭包types的函数调用操作符相同的参数和返回types的函数。 这个转换函数返回的值应该是被调用的函数的地址,和调用闭包types的函数调用操作符一样。

这一点很重要,因为一元运算符+有一组内置的重载,特别是这一个:

13.6内置运算符[over-built]

8对于每个typesT ,都存在表格的候选操作符函数

T* operator+(T*);

并且,很明显会发生什么:当operator +应用于闭包对象时,重载的内build候选集合包含一个转换为任意指针,并且闭包types恰好包含一个候选:转换为函数lambda的指针。

auto test = +[]{};testtypesauto test = +[]{}; 因此被推断为void(*)() 。 现在,第二行很容易:对于第二个lambda / closure对象,函数指针的赋值会触发与第一行相同的转换。 即使第二个lambda具有不同的闭包types,所产生的函数指针当然是兼容的,并且可以被赋值。