为什么lambda按值捕获x时decltype(x)在原x为引用时返回引用类型
原因解释
这个现象是C++标准对lambda简单捕获的decltype推导规则的明确规定,并非编译器bug,核心规则如下:
对于lambda的简单按值捕获(即形如[x]这种直接写变量名的捕获,非初始化捕获):
- 在lambda函数体内使用被捕获的标识符
x时,除了作为decltype的操作数的场景外,均指代闭包对象内部生成的拷贝成员 - 当
x作为decltype的操作数时,decltype直接推导原外部被捕获变量的类型,而非闭包内部拷贝成员的类型
各示例行为说明
示例1:foo函数
void foo() { int y = 0; int& x = y; [x]() { static_assert(std::is_same_v<decltype(x), int&>); return x; }(); }
外部原变量x的类型是int&,因此decltype(x)直接推导原变量类型得到int&,与断言一致,编译通过。但要注意:lambda内除decltype场景外使用x时,操作的都是内部生成的int类型拷贝,而非原外部引用。
示例2:foo2函数
void foo2() { int y = 0; int x = y; [x]() { static_assert(std::is_same_v<decltype(x), int>); return x; }(); }
外部原变量x的类型本身就是int,因此decltype(x)推导结果和闭包内拷贝成员的类型一致,看起来行为符合直觉,不会暴露规则差异。
示例3:foo3函数
void foo3() { int y = 0; int& x = y; [z = x]() { static_assert(std::is_same_v<decltype(z), int>); return z; }(); }
这里使用的是初始化捕获,捕获变量z是lambda内新声明的实体,没有对应的外部原捕获变量,因此decltype(z)直接推导z本身的类型:用x(int&)拷贝初始化得到的是int类型,因此断言通过,符合预期。
补充说明
如果想要获取闭包内部拷贝成员的类型,可以通过间接方式获取,比如用decltype((x)):括号包裹后不再触发特殊规则,推导的是左值表达式的类型,对于int类型的左值成员,decltype((x))会得到int&;如果要拿到纯值类型,可以用std::decay_t<decltype(x)>处理。
内容的提问来源于stack exchange,提问作者nicolai
相关产品推荐
相关产品推荐

