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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逗号运算符使lambda表达式非constexpr相关的知识,希望对你有一定的参考价值。

根据[this Q&A],因为c ++ 11逗号运算符是constexpr能力。根据[this Q&A],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()>{});
}

编译错误:

变量'c'不能在没有指定capture-default的lambda中隐式捕获

[live demo]

答案

根据[basic.def.odr]/4,它似乎是一个铿锵的bug:

变量x的名称显示为可能被评估的表达式ex,除非将lvalue-to-rvalue转换(7.1)应用于x,产生不调用任何非平凡函数的常量表达式(8.20),否则由ex使用odr。 ,如果x是一个对象,则ex是表达式e的潜在结果集合的元素,其中左值到右值的转换(7.1)应用于e,或者e是丢弃值表达式。

正如已经评论过的那样,问题不仅限于逗号运算符,而是对于每个丢弃的表达式,这些表达式不构成使用odr,因此必须接受它。

另一答案

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

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

clang也认为这个格式不正确(see it live),lambda需要捕获一个自动变量,如果它使用它看到expr.prim.lambda.capturep8

如果明确或隐式捕获实体,则捕获该实体。由lambda表达式捕获的实体在包含lambda表达式的作用域中使用odr。如果* this由本地lambda表达式捕获,则其最近的封闭函数应为非静态成员函数。如果一个lambda表达式或一个普通lambda odr的函数调用操作符模板的实例化使用这个或一个自动存储持续时间到达其范围的变量,那么该实体应该被lambda表达式捕获。如果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

以上是关于逗号运算符使lambda表达式非constexpr的主要内容,如果未能解决你的问题,请参考以下文章

lambda表达式

lambda表达式

Lambda表达式

Lambda表达式总结

C# Lambda表达式详细总结

constexpr