我可以在 lambda 中使用 constexpr 值而不捕获它吗?

Posted

技术标签:

【中文标题】我可以在 lambda 中使用 constexpr 值而不捕获它吗?【英文标题】:Can I use a constexpr value in a lambda without capturing it? 【发布时间】: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:这只是一个口头禅。从这里引用:***.com/questions/14041453/…“宏就像任何其他工具一样 - 用于谋杀的锤子不是邪恶的,因为它是一把锤子。人们以这种方式使用它的方式是邪恶的。如果你想锤钉子,锤子是完美的工具。” 【参考方案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

以上是关于我可以在 lambda 中使用 constexpr 值而不捕获它吗?的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 2015 在 constexpr 中使用 lambda

我可以将 C++17 无捕获 lambda constexpr 转换运算符的结果用作函数指针模板非类型参数吗?

使用 lambda 捕获的 constexpr 值作为数组维度

if constexpr 在模板化 lambda 中未丢弃的错误分支

未捕获 constexpr 变量

constexpr lambda / ‘x’ 没有命名类型;你的意思是“x”吗?