一个积极的lambda:'+ [] {}' - 这是什么巫术?

Dan*_*rey 255 c++ lambda operator-overloading language-lawyer c++11

在Stack Overflow问题中,在C++ 11中不允许重新定义lambda,为什么?,给出了一个不编译的小程序:

int main() {
    auto test = []{};
    test = []{};
}
Run Code Online (Sandbox Code Playgroud)

问题得到了回答,一切似乎都很好.然后是Johannes Schaub并做了一个有趣的观察:

如果你+在第一个lambda之前放置一个,它会神奇地开始工作.

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

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

它与GCC 4.7+和Clang 3.2+都很好.代码标准是否符合要求?

Dan*_*rey 240

是的,代码符合标准.所述+触发转换为拉姆达一个普通的旧函数指针.

这是怎么回事:

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

5.1.2 Lambda表达式[expr.prim.lambda]

6没有lambda-capturelambda表达式的闭包类型有一个公共的非虚拟非显式const转换函数,用于指向具有与闭包类型的函数调用操作符相同的参数和返回类型的函数.此转换函数返回的值应为函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果.

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

13.6内置运算符[over.built]

8对于每种类型T,都存在表单的候选运算符函数

    T* operator+(T*);

有了这个,很明显会发生什么:当operator +被应用于闭包对象时,重载的内置候选集包含一个转换为任意指针,闭包类型只包含一个候选:转换为函数lambda的指针.

因此推断出testin 的类型.现在第二行很简单:对于第二个lambda/closure对象,对函数指针的赋值触发与第一行相同的转换.即使第二个lambda具有不同的闭包类型,结果函数指针当然也是兼容的并且可以被赋值.auto test = +[]{};void(*)()

  • 如果您想强制数组或函数的衰减,并且您想要强制推广小整数类型或未范围的枚举,这将非常有用. (19认同)
  • 迷人.指针的一元"+"有什么意义?我理解它存在于数字类型的完整性与一元`-`.但是带指针的一元`-`毫无意义. (17认同)
  • @TadeuszKopec ......对于所有类型,它都会删除左值.您可以使用它来传递值而不是对两者上重载的函数的引用,例如通过完美转发. (5认同)