c++ - 正 lambda : '+[]{}' - What sorcery is this?

标签 c++ c++11 lambda operator-overloading language-lawyer

<分区>

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

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

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

If you put a + before the first lambda, it magically starts to work.

所以我很好奇:为什么下面的方法有效?

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 Lambda expressions [expr.prim.lambda]

6 The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

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

13.6 Built-in operators [over.built]

8 For every type T there exist candidate operator functions of the form

    T* operator+(T*);

有了这个,很清楚会发生什么:当运算符 + 应用于闭包对象时,重载的内置候选集包含一个转换为任意指针和闭包类型只包含一个候选者:到 lambda 函数指针的转换。

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

关于c++ - 正 lambda : '+[]{}' - What sorcery is this?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49395601/

相关文章:

c++ - 可以使 C++ 枚举大于 64 位吗?

java - 如何使用 java-stream 比较两个文件并找到某个分组中的值之和?

c++ - 在 C++ 中多次调用同一个 lambda

C++对删除错误

c++ - 尝试将 std::cerr 重定向到文件时出现访问冲突异常

c++ - 在可变参数函数内的不同参数包中推导出两个不同的已知类型变量

c++ - 将 char 直接放在数组后的可靠方法

java - Lambda 性能改进,Java 8 对比 11

c++ - 正则表达式 C++ : extract substring

c++ - 编写自己的流媒体运算符时如何检查当前的 ostream dec/hex 模式?