【问题标题】:Can I use a constexpr value in a lambda without capturing it?我可以在 lambda 中使用 constexpr 值而不捕获它吗?
【发布时间】:2016-02-25 17:18:47
【问题描述】:

我想在 lambda 中使用 constexpr 值。阅读答案 Using lambda captured constexpr value as an array dimension,我认为以下应该可行:

  #include<array>
  int main()
  { 
    constexpr int i = 0;
    auto f = []{  
      std::array<int, i> a;
    };
    return 0;
  }

但是,Clang 3.8(带有 std=c++14)抱怨

变量 'i' 不能在 lambda 中隐式捕获,没有 指定默认捕获

这应该被认为是 clang 3.8 中的一个错误吗?

顺便说一句:

上面的代码可以用 gcc 4.9.2 编译。 如果我将 lambda 表达式更改为显式捕获:

...
auto f = [i]{
...

clang 3.8 编译它,但 gcc 4.9.2 失败:

错误:‘i’的值在常量表达式中不可用 ...

【问题讨论】:

  • [constexpr int _i =i]{} 有什么不同吗?
  • 不,在 gcc 4.9.2 和 Clang 3.8 下都不能编译。
  • hmmm.... 我猜你认为 #define 作为(临时)解决方案?
  • 但是宏是邪恶的!另外,它们不能用 constexpr 函数赋值。
  • @GuillaumeRacicot:这只是一个口头禅。从这里引用:stackoverflow.com/questions/14041453/…“宏就像任何其他工具一样 - 用于谋杀的锤子不是邪恶的,因为它是一把锤子。人们以这种方式使用它的方式是邪恶的。如果你想锤钉子,锤子是完美的工具。”

标签: c++ lambda c++14 constexpr


【解决方案1】:

这应该被认为是 clang 3.8 中的一个错误吗?

是的。仅当 [expr.prim.lambda]/12 要求时才需要捕获:

请特别注意突出显示的示例。 f(x) 不需要捕获 x,因为它不是 odr 使用的(重载分辨率选择带有 object 参数的重载)。同样的论点适用于您的代码 - [basic.def.odr]/3:

变量x,其名称显示为潜在评估表达式 exex odr 使用 除非应用左值到右值的转换 (4.1) 到x 产生一个不调用的常量表达式 (5.20) 任何重要的功能……

这个要求肯定满足。

...并且,如果x 是一个对象,ex 是一个元素 表达式e 的一组潜在结果,其中 左值到右值转换 (4.1) 应用于 e,或者 e 是 丢弃值表达式(第 5 条)。

i 是其根据 [basic.def.odr]/(2.1) 的一组潜在结果,并且当它传递给对象类型的非类型模板参数时,确实会立即应用 ltr 转换。

因此,正如我们已经证明 (12.1) 不适用 - 而 (12.2) 显然也不适用 - Clang 拒绝您的 sn-p 是错误的。

【讨论】:

  • 该标准似乎并没有在 lambdas 中使用 constexpr 花费太多文字......示例中的代码仅处理运行时使用(对吗?),并且在 clang 3.8 和g++ 4.9.2.
  • 无论如何,在clang中确实看起来是错误的。我提交了错误llvm.org/bugs/show_bug.cgi?id=25627 .
  • @OlafBooij 关键是它不能作为运行时(=odr-)使用,因为没有捕获变量。它编译的事实是......不言自明,因为它的目的是,开发人员甚至可能已经用那个确切的例子测试了东西。
  • 唉,MSVC,在 C++11 之后整整十年,仍然没有编译器可以正确实现它; MSVC 坚持明确捕获i
猜你喜欢
  • 2019-08-03
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
相关资源
最近更新 更多