当我编译以下程序(https://wandbox.org/permlink/fl6yrLYI2sRrZJHP)
#include <iostream>
using std::cout;
using std::endl;
template <typename...> class WhichType;
int main() {
const auto& integer = 0;
[integer]() {
WhichType<decltype(integer)>{};
}();
}
为什么编译器说decltype(integer)
是const int&
?我的理解是,这应该是const int
,而decltype((integer))
应该已经解析为const int&
。
换句话说,我的理解是lambda会解析为这样的结构
struct Lambda {
public:
explicit Lambda(const int& integer_) : integer{integer_} {}
void operator()() const {
WhichType<decltype(integer)>{};
}
const int integer;
};
为什么decltype(integer)
会解析为引用类型?这是decltype
的另一种特殊行为吗?类似于结构化绑定中的引用类型和实际类型区别?
答案 0 :(得分:1)
此行为似乎是标准规定的。似乎是decltype()
在lambda中的特定例外:
8.1.5.2 Captures [expr.prim.lambda.capture]
...
14 Every occurrence of decltype((x)) where x is a possibly parenthesized id-
expression that names an entity of automatic storage duration is treated as if x
were transformed into an access to a corresponding data member of the closure
type that would have been declared if x were an odr-use of the denoted entity.
Example:
void f3() {
float x, &r = x;
[=] { // x and r are not captured (appearance in a decltype operand is not an odr-use)
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda is
// not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float& (transformation not considered)
decltype((r)) r2 = y2; // r2 has type float const&
};
}
— end example ]
那里的关键词似乎是“不考虑转变”。
答案 1 :(得分:1)
这里有两个相关规则。
在lambda中引用某些东西意味着什么?在expr.lambda.prim.capture中,请强调:
在 lambda表达式 的 compound-statement 中的每个 id-expression ,被复制捕获的实体的>转换为对闭包类型的相应未命名数据成员的访问。
然后decltype
是什么意思?在[dcl.type.simple]中:
对于表达式
e
,由decltype(e)
表示的类型定义如下: -[...]
-否则,如果e
是未括号的 id-expression 或未括号的类成员访问,则decltype(e)
是由e
命名的实体的类型。如果没有这样的实体,或者如果e
命名一组重载函数,则程序的格式不正确;
decltype(integer)
不是integer
的奇特用法,因此它只是integer
的类型,即const int&
。实际上,这是decltype
的最普通的含义-只是变量的类型(只是在您可能认为它是发明捕获的类型的情况下-尽管在这种情况下,发明捕获的类型只是int
,而不是const int
)。
您出问题的地方是如何为lambda命名合成类型的成员变量。更准确的是:
int main() {
const auto& integer = 0;
struct __lambda {
int __integer;
auto operator() const {
WhichType<decltype(integer)>{}; // NB: still integer, not __integer, because not an odr-use
};
}
__lambda{integer}();
}
有一个专门针对decltype((x))
的规则,在这种情况下,实际上decltype((integer))
仍然是const int&
,但出于不同的原因,但是该规则是{{ 3}},该措辞已从最新的工作草案中删除。