这编译
void f() {
constexpr bool x{};
auto g = []{
if constexpr (x) {
}
};
g();
}
int main () {
f();
}
即使我将[]
更改为[x]
或[&x]
,它也可以编译.不过,在后两种情况下,clangd告诉我。
对于此用途,不需要捕获 Lambda 捕获"x"(修复可用)[-Wunused-lambda-capture]
第一个小问题是:在这种情况下捕获x
是否只是多余的?还是还有更多?
但我的主要问题是:在上述情况下,我应该从标准的哪个地方了解我可以在没有任何捕获的情况下进行?毕竟,例如,只是在if constexpr
之前写(void)x;
,使得捕获([x]
或[&x]
)是必要的。
如果变量是在 lambda 表达式中使用 odr 的局部实体,则需要捕获该变量。参见 [basic.def.odr]/10。在您的示例中,x
是一个本地实体,但if constexpr (x)
不使用它,因为:
x
是非引用类型的变量,可在常量表达式中使用,并且没有可变的子对象,并且- 立即应用左值到右值的转换。
请参阅 [basic.def.odr]/5.2。(在有限的情况下,不允许立即进行左值到右值的转换;请参阅 [basic.def.odr]/3。
通常,当您需要确定变量是否使用 odr 时,[basic.def.odr]/5 是查找的位置。
这种情况是ODR用法(或者更确切地说:在这种特殊情况下是非ODR用法),它不是特定于C++20的。
参见expr.prim.lambda.capture
如果表达式可能引用了该表达式在其中可用的声明性区域中的本地实体,并且 如果任何封闭的类型 ID 表达式 (7.6.1.7) 的效果 忽略,该实体被称为由每个具有关联 捕获默认值,不显式捕获它。
查看以下示例和注释也可能是值得的:
注意:捕获的实体集是通过语法确定的,实体甚至可能被隐式捕获 如果表示局部实体的表达式位于丢弃语句 (8.5.1) 中。例:
template<bool B>
void f(int n) {
[=](auto a) {
if constexpr (B && sizeof(a) > 4) {
(void)n; // captures n regardless of the value of B and sizeof(int)
}
}(0);
}
在以前的标准中,恕我直言,它更明确地说明,请参阅:https://stackoverflow.com/a/42611583/4885321