【问题标题】:comma operator makes lambda expression non-constexpr逗号运算符使 lambda 表达式成为非 constexpr
【发布时间】:2019-04-25 11:32:45
【问题描述】:

根据[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),但以下 sn-p 没有,我无法想象为什么......有什么想法吗?

template <int>
struct Foo {};

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

编译错误:

在未指定捕获默认值的 lambda 中无法隐式捕获变量“c”

[live demo]

【问题讨论】:

  • 不是答案,但是......在 wandbox clang++ 中抱怨,因为“变量 'c' 无法在未指定捕获默认值的 lambda 中隐式捕获”;通过引用捕获 ([&amp;]) 抱怨,因为“对 'c' 的引用不是常量表达式”;按值捕获 ([=]) 编译没有问题。有趣的是,g++ 在所有三种情况下都可以毫无问题地编译。
  • 我认为逗号操作符引用了c,并且引用break constexpr
  • clang 错误?我不是语言层,所以坦率地说,我不知道。
  • 但完美运行constexpr auto lambda = []{ auto a=c; return a;};;所以c 值没有问题,但是当c 被视为对c 的引用时出错?
  • 只需在 bugs.llvm.org 上记录一个错误,因为它不同,一个答案似乎表明 GCC 是正确的

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


【解决方案1】:

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

变量 x 其名称显示为潜在求值表达式 ex 被 ex odr 使用,除非将左值到右值转换 (7.1) 应用到 x 产生不调用任何非-普通函数,如果 x 是一个对象,ex 是表达式 e 的潜在结果集合中的一个元素,其中左值到右值转换 (7.1) 应用于 e, 或 e 是被丢弃的-值表达式

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

【讨论】:

    【解决方案2】:

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

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

    clang 还认为这种格式不正确 (see it live),如果 lambda 使用 odr 来捕获自动变量,请参见 expr.prim.lambda.capturep8

    如果实体被显式或隐式捕获,则该实体被捕获。由 lambda 表达式捕获的实体在包含 lambda 表达式的范围内使用。如果 *this 被本地 lambda 表达式捕获,则其最近的封闭函数应为非静态成员函数。如果 lambda 表达式或泛型 lambda 的函数调用运算符模板的实例化 odr-使用 this 或从其到达范围内具有自动存储持续时间的变量,则该实体应由 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 的情况下也对其进行了测试,但显然我错过了......所以你可能是对的,问题更深层次......
    猜你喜欢
    • 1970-01-01
    • 2011-07-21
    • 2019-02-07
    • 1970-01-01
    • 2016-06-14
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    相关资源
    最近更新 更多