将 lambda 中捕获的 const 值用作模板参数是不是合法?

Posted

技术标签:

【中文标题】将 lambda 中捕获的 const 值用作模板参数是不是合法?【英文标题】:Is it legal to use a const value captured in a lambda as a template argument?将 lambda 中捕获的 const 值用作模板参数是否合法? 【发布时间】:2018-04-04 16:02:28 【问题描述】:

考虑以下由同事提供的代码:

#include <array>
#include <string>

int main() 
    const int size = 4;
    return [size]() 
      std::array<std::string, size> a; // *
      return a.size();
    ();

它被 Clang 5.0.0 接受,但被 GCC 7.2 拒绝,带星号的行的错误消息是:

error: '__closure' is not a constant expression

哪个编译器是正确的?

【问题讨论】:

用gcc 8编译。 我原以为它不应该编译,但闭包变成了一个难题中的一个谜。 如果我理解正确的话,CV 限定符会跟随副本捕获。因此,Clang 是正确的。 【参考方案1】:

该规则实际上很直观:任何不需要捕获的变量都指的是原始变量。 [expr.prim.lambda]/11:

复合语句中的每个id-expression lambda-expression 是对通过副本捕获的实体的 odr 使用 转化为对相应未命名数据成员的访问 闭包类型。 [ 注意:一个 id-expression 不是 odr-use 指的是原始实体,绝不是闭包类型的成员。 […] — 尾注 ]

显然,声明的size变量可以用在常量表达式中,因此Clang是对的。

【讨论】:

以上是关于将 lambda 中捕获的 const 值用作模板参数是不是合法?的主要内容,如果未能解决你的问题,请参考以下文章

C ++ 0x lambda按值捕获总是const?

对成员函数的模糊调用以在 lambda 中捕获 this

这个 lambda 捕获参数中的 const-ness 是在哪里引入的?

C++20:非类型模板参数中的非捕获 lambda

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

g++ 不允许在 lambda 中通过引用对 const 对象进行广义捕获?