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

comma operator makes lambda expression non-constexpr

根据 [this Q&A] since c++11 comma operator is constexpr capable. According to [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()>{});
}

编译错误:

variable 'c' cannot be implicitly captured in a lambda with no capture-default specified

[live demo]

根据[basic.def.odr]/4:

,这似乎是一个 clang bug

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (7.1) to x yields a constant expression (8.20) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (7.1) is applied to e, or e is a discarded-value expression.

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

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

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

clang 也认为这种格式错误 (see it live), the lambda is required to capture an automatic variable if it odr-uses it see expr.prim.lambda.capturep8:

An entity is captured if it is captured explicitly or implicitly. An entity captured by a lambda-expression is odr-used in the scope containing the lambda-expression. If *this is captured by a local lambda expression, its nearest enclosing function shall be a non-static member function. If a lambda-expression or an instantiation of the function call operator template of a generic lambda odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression. If a lambda-expression captures an entity and that entity is not defined or captured in the immediately enclosing lambda expression or function, the program is ill-formed. ...

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