【问题标题】:Why this code fails to compile with gcc 4.8.5 while it compiles fine with clang为什么此代码无法使用 gcc 4.8.5 编译,而使用 clang 可以正常编译
【发布时间】:2018-12-06 05:16:11
【问题描述】:
#include<iostream>                                                                                                                                    

using namespace std;                                                                                                                                  

int main()                                                                                                                                            
{                                                                                                                                                     
   const int k = 10;                                                                                                                                  

   // Capture k by value                                                                                                                              
   auto myl = [k] (int k) { cout << " ++k=" << ++k ; };                                                                                            

   myl(k+10);                                                                                                                                             
}  

以下错误

lamda.cpp: In lambda function:
lamda.cpp:10:50: error: increment of read-only variable âkâ
    auto myl = [k] (int k) { cout << " ++K=" << ++k ; };

显然我指的是局部变量 K 而不是 const 成员 K。

【问题讨论】:

  • 你确定你可以用 Clang 编译它吗?您有名称拦截,因为您与名为 k 的 lambda 函数形式参数共享常量“k”。如果 clang 能够编译它 - 您可能可以使用 GCC 5+ 和 -std=c++14 键对其进行测试。无论如何,您的代码都有错误。
  • 除了 8.1 之外的所有 gcc 编译器都失败了,我们可以在这里看到它。godbolt.org/g/o355oQ
  • 也许相关的是 GCC 8.1 支持 C++2a 的某些特性,所以也许是故意的。
  • 这与c++2无关clang从3.4.1版本开始编译godbolt.org/g/B46sX9

标签: c++ c++11 gcc clang gcc4.8


【解决方案1】:

这并不像看起来那么简单。通过复制捕获k 的 lambda 几乎等同于一个结构对象,其闭包类型具有一个名为 k 的成员,并且具有一个 operator(),其定义使用指定的参数和主体。如果这在技术上是正确的,当然,我们知道函数参数隐藏了类成员。

除了标准实际上不是这样定义 lambda 的。相反,它表示任何由值捕获的实体都对应于闭包类型的 unnamed 成员。在 lambda 主体中,名称查找在 lambda 的封闭范围内查找,而不是在闭包类型的范围内。如果该名称查找找到由副本捕获的实体,则编译器必须在内部将该名称的用法转换为未命名成员的用法。在 C++11 和 C++14 中,这些规则没有明确指定 lambda 参数名称如何适合该名称查找方案,因此,不同的编译器和编译器版本在这种情况下的行为不一致捕获的实体和 lambda 参数具有相同的名称。

使用Defect Resolution 2211,C++17 解决了这个问题,只是将其设为非法:

[expr.prim.lambda.capture]/5:

如果 simple-capture 中的 identifier 出现为 lambda-declaratordeclarator-id /em> 的 parameter-declaration-clause,程序格式错误。 [ 例子:

void f() {
  int x = 0;
  auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name
}

-- 结束示例 ]

(另见当前草稿镜中的the same paragraph。)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-08
  • 2017-01-11
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多