逗号运算符使lambda表达式成为非constexpr

时间:2018-11-22 18:57:50

标签: c++ lambda language-lawyer c++17 constexpr

根据[this Q&A],因为c ++ 11逗号运算符具有constexpr功能。根据{{​​3}},constexpr变量不应被lambda捕获,而应在其体内使用。

这两个规则使以下代码可以在clang中编译:

//Example 1

template <int>
struct Foo {};

int main() {
    constexpr int c = 1;
    static_cast<void>(Foo<(c, 2)>{});
}

//Example 2

template <int>
struct Foo {};

int main() {
    constexpr int c = 1;
    auto lambda = []{return c * 2;};
    static_cast<void>(Foo<lambda()>{});
}

尽管这两个示例都在clang上成功编译(声明了constexpr lambda支持-8.0.0),但以下代码段却没有,我无法想象为什么...有什么想法?

template <int>
struct Foo {};

int main() {
    constexpr int c = 1;
    auto lambda = []{return (c, 2);};
    static_cast<void>(Foo<lambda()>{});
}

编译错误:

  

在未指定捕获默认值的lambda中,不能隐式捕获变量“ c”

[this Q&A]

2 个答案:

答案 0 :(得分:5)

根据[basic.def.odr]/4,这似乎是一个叮叮当当的错误:

  

除非变量x的名称显示为可能评估的表达式ex,否则ex会使用它,除非对x应用左值到右值转换(7.1)会产生一个常量表达式(8.20),该表达式不会调用任何非-琐碎函数,如果x是一个对象,则ex是表达式e的一组潜在结果的元素,其中将左值到右值转换(7.1)应用于e,或e被丢弃-值表达式

如前所述,问题不仅限于逗号运算符,对于每个丢弃的表达式,这些表达式也不构成 odr-use ,因此必须接受。

答案 1 :(得分:3)

如果我们看一个更简单的案例,这是一个叮叮当当的错误:

constexpr int c = 1;
auto lambda =  [] {return c,2;};

clang也认为此格式不正确(see it live),如果lambda odr-use参见expr.prim.lambda.capturep8,则需要lambda来捕获自动变量:

  

如果显式或隐式捕获实体,则捕获该实体。由lambda表达式捕获的实体会在包含lambda表达式的范围内使用。如果*这是由本地lambda表达式捕获的,则其最接近的封闭函数应为非静态成员函数。如果通用lambda odr的lambda表达式或函数调用操作符模板的实例使用该变量或具有达到其作用域的自动存储持续时间的变量,则该实体应由lambda-expression捕获。如果lambda表达式捕获了一个实体,而该实体未在紧随其后的lambda表达式或函数中定义或捕获,则程序格式错误。 ...

discarded value expression is not an odr-use

我找到了类似的bug report [rejects valid] constexpr non-scalar variable not usable in lambda without capture or local class