C++20中丢弃值表达式与odr-used疑问:未捕获局部变量为何报错
C++20 Lambda未捕获局部变量报错的原因解析
先看你的示例代码:
#include <iostream> using namespace std; int main() { int n=1; []() { n;// (1): 错误 }(); }
你对odr-used规则的理解是对的:这里单独的n是丢弃值表达式,且没有触发左值到右值转换,所以n确实没有被odr-used。但代码报错的核心原因,是你忽略了C++20中lambda捕获的补充规则:
关键规则补充
C++20标准中,lambda表达式对外部局部实体的使用,除了odr-used的场景外,还有一条要求:
如果局部实体在lambda的潜在求值表达式中被命名(且不属于未求值操作数,比如
sizeof的参数),即使它没有被odr-used,也必须被捕获——要么显式写出捕获列表,要么通过捕获默认值([=]或[&])隐式捕获。
代码错误的具体原因
你的lambda既没有显式捕获n,也没有设置捕获默认值,完全没有满足对n的捕获要求,因此编译器会报错。
再结合你引用的odr-usable规则来看:n在lambda的块作用域中属于非odr-usable状态——因为lambda的参数作用域作为中间声明区域,既不是块作用域,lambda也没有捕获n或设置捕获默认值。不过这个规则的触发条件是“在非odr-usable区域中odr-used”,而你代码的错误本质是违反了lambda的捕获规则,和odr-usable的直接关联不大。
修复方案
要让代码合法,有两种简单方式:
- 显式捕获
n:[n](){ n; }(); - 使用捕获默认值(按值或按引用):
[=](){ n; }(); // 按值捕获 // 或者 [&](){ n; }(); // 按引用捕获
内容的提问来源于stack exchange,提问作者Red
相关产品推荐
相关产品推荐

