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



根据[this Q&A],由于c++11逗号运算符具有constexpr功能。根据[thisQ&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上成功编译(它声明了--8.0.0的constexpr lambda支持(,但下面的代码段却没有,我无法想象为什么。。。有什么想法吗?

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

编译错误:

变量"c"不能在没有指定捕获默认的lambda中隐式捕获

[现场演示]

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

变量x的名称显示为潜在求值表达式ex,除非将左值到右值的转换(7.1(应用到x会产生一个不调用任何非平凡函数的常量表达式(8.20(,并且如果x是对象,则ex是表达式e的潜在结果集的元素,其中左值到右值的转换(7.1(应用于e,或e是一个丢弃的值表达式

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

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

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

clang还认为这是一个不正确的形式(请参阅实时(,如果它odr使用lambda,则需要lambda来捕获自动变量请参阅expr.prim.lambda.capturep8:

如果显式或隐式捕获实体,则会捕获该实体。lambda表达式捕获的实体在包含lambda表达式的作用域中使用odr。如果*this被局部lambda表达式捕获,则其最近的封闭函数应为非静态成员函数。如果lambda表达式或泛型lambdaodr的函数调用运算符模板的实例化使用此变量或从其到达范围起具有自动存储持续时间的变量,则该实体应被lambda表达式捕获。如果lambda表达式捕获了一个实体,而该实体没有在直接封闭的lambda表达式或函数中定义或捕获,则程序格式错误。。。

和丢弃的值表达式不是odr用法。

我发现一个类似的错误报告[拒绝有效的]constexpr非标量变量在没有捕获或本地类的lambda中不可用。

最新更新