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

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

堆栈溢出问题 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*);

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

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

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

相关文章:

c++ - 对是否条件 CPP 感到困惑

java - 如何在循环体中写条件?

c++ - 如何通过指向类实例的指针获取LLDB中类的成员

c++ - 物理引擎的循环模板类型名依赖

c++ - 当 typedef 名称与可变参数模板参数名称一致时出现 GCC 错误

c++ - boost 绑定(bind)编译错误

c++ - 构造函数和析构函数对 vTable 的 undefined reference

haskell - 共享部分应用功能

c++ - 在结构 C++ 的 vector 中使用 find_if 和 remove_if

c# - 使用 lambda 从 List 获取数组数组?