一个正面的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对于每个types
T
,都存在表格的候选操作符函数
T* operator+(T*);
并且,很明显会发生什么:当operator +
应用于闭包对象时,重载的内build候选集合包含一个转换为任意指针,并且闭包types恰好包含一个候选:转换为函数lambda的指针。
auto test = +[]{};
的test
typesauto test = +[]{};
因此被推断为void(*)()
。 现在,第二行很容易:对于第二个lambda / closure对象,函数指针的赋值会触发与第一行相同的转换。 即使第二个lambda具有不同的闭包types,所产生的函数指针当然是兼容的,并且可以被赋值。