关于Lambda捕获实体的decltype(),哪款编译器符合ISO C++17标准?
Lambda捕获与decltype的编译器合规性分析
测试代码
#include <iostream> #include <type_traits> int main(){ int i = 1; int& j = i; auto f2 = [j = j]() { std::cout << std::is_same_v<decltype(j), int&> << std::is_same_v<decltype((j)), int&> << std::is_same_v<decltype((j)), const int&>; }; auto f3 = [=]() { std::cout << std::is_same_v<decltype(j), int&> << std::is_same_v<decltype((j)), int&> << std::is_same_v<decltype((j)), const int&>; }; f2(); f3(); }
C++17下各编译器输出
| gcc | clang | msvc |
|---|---|---|
| 001 | 001 | 010 |
| 110 | 101 | 101 |
标准规则与合规性判断
1. 初始化捕获f2 = [j = j]()的分析
根据C++17标准:
- 初始化捕获
[j = j]等价于auto j = j,外部的j是int&类型,auto推导会忽略引用,因此Lambda闭包的成员j类型为int。 - Lambda的
operator()默认是const成员函数,因此闭包成员j在函数体内是const左值。decltype(j):取变量本身的类型,结果为int,因此第一个输出为0。decltype((j)):带括号的表达式是const左值,类型为const int&,因此第二个输出为0,第三个输出为1。
- 合规结论:
f2的正确输出是001,gcc和clang符合标准,msvc输出010不符合标准。
2. 值捕获f3 = [=]()的分析
根据C++17标准:
- 值捕获引用变量
j时,闭包的成员类型为被引用的类型(即int),而非引用类型。Lambda内部的j是该成员的名字,类型为int。 - 同样,
operator()是const成员函数,成员j在函数体内是const左值。decltype(j):变量类型为int,第一个输出应为0。decltype((j)):表达式类型为const int&,第二个输出应为0,第三个输出应为1。
- 合规结论:
f3的正确输出应为001,但三款编译器的输出均不符合此结果,说明三款编译器在值捕获引用变量的decltype处理上均存在错误。
总结
- 对于初始化捕获场景,gcc和clang符合C++17标准,msvc存在错误。
- 对于值捕获引用变量的场景,三款编译器均不符合C++17标准。
内容的提问来源于stack exchange,提问作者余国良
相关产品推荐
相关产品推荐

