提问人:Bernard 提问时间:3/5/2017 更新时间:3/6/2017 访问量:1397
constexpr 表达式必须由 C++ 中的 lambda 捕获吗?
Must constexpr expressions be captured by a lambda in C++?
问:
下面是一段不会在 MSVC 2015 中编译的代码(忽略未初始化的值访问):
#include <array>
int main() {
constexpr int x = 5;
auto func = []() {
std::array<int, x> arr;
return arr[0];
};
func();
}
它抱怨说:
'x' cannot be implicitly captured because no default capture mode has been specified
但是是一个 ! 在编译时已知为 。为什么 MSVC 对此大惊小怪?(这是另一个 MSVC 错误吗?GCC很乐意编译它。x
constexpr
x
5
答:
-2赞
Sam Varshavchik
3/5/2017
#1
即使 是 ,它与任何其他对象没有什么不同,否则,并且在范围方面遵循相同的规则。对 s 的作用域规则没有例外,并且必须对 lambda 进行编码以显式捕获它。x
constexpr
constexpr
评论
0赞
Bernard
3/5/2017
那么有没有办法捕获它,但允许我像在我的代码中一样将其用作模板参数?
0赞
Walter
3/5/2017
这是另一个问题。
0赞
DeiDei
3/6/2017
clang 允许您捕获它,然后将其用作模板参数,但 GCC 没有。我很困惑。[x]() {...}
1赞
yuri kilochek
3/6/2017
@Bernard只要成功,就不需要捕捉。static
6赞
Barry
3/6/2017
不,事实并非如此,-1。
13赞
Barry
3/6/2017
#2
代码格式正确。[expr.prim.lambda] 中的规则是:
如果 lambda-expression 或函数调用函数的实例化 通用 lambda odr-uses (3.2) 或具有 自动存储持续时间 从其到达范围,该实体应由 lambda-expression 捕获。
this
必须捕获 odr 使用的任何变量。lambda-expression 中使用了 odr 吗?不,不是。[basic.def.odr] 中的规则是:x
除非应用左值到右值的转换 (4.1) 来生成一个不调用任何非平凡的常量表达式 (5.20),否则其名称显示为潜在计算表达式的变量由 odr 使用 函数 和 (如果 是对象) 是表达式 的 潜在结果集的一个元素 ,其中左值到右值的转换 (4.1) 应用于 ,或者是丢弃值表达式(第 5 条)。
x
ex
ex
x
x
ex
e
e
e
x
仅在我们应用左值到右值转换并最终得到常量表达式的上下文中使用,因此它不使用 ODR,因此我们不需要捕获它。该程序很好。这与为什么标准中的这个示例格式正确的想法相同:
void f(int, const int (&)[2] = {}) { } // #1 void f(const int&, const int (&)[1]) { } // #2 void test() { const int x = 17; auto g = [](auto a) { f(x); // OK: calls #1, does not capture x }; // ... }
评论
std::array<int, x
> 更改为std::array<int, +x>,
Clang 会接受此操作。