首页 文章

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

提问于
浏览
249

这个问题在这里已有答案:

在Stack Overflow问题Redefining lambdas not allowed in C++11, why?中,给出了一个不编译的小程序:

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

问题得到了回答,一切似乎都很好 . 然后来了Johannes Schaub并制作了an interesting observation

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

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

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

它与GCC 4.7和Clang 3.2编译良好 . 代码标准是否符合要求?

1 回答

  • 230

    是的,代码符合标准 . + 触发转换为lambda的普通旧函数指针 .

    这是怎么回事:

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

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

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

    13.6内置运算符[over.built] 8对于每个类型T,存在T *运算符(T *)形式的候选运算符函数;

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

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

相关问题