考虑以下情况:
std::tuple<int, int&>& foo();
auto& [x, y] = foo();
什么是decltype(x)
和什么是decltype(y)
?语言功能的目标是x
成为foo().__0
和y
的另一个名称foo().__1
,这意味着它们应该分别是int
和int&
。正如今天所指定的,这将解压缩为†:
auto& __e = foo();
std::tuple_element_t<0, decltype(__e)>& x = std::get<0>(__e);
std::tuple_element_t<1, decltype(__e)>& y = std::get<1>(__e);
并且规则的工作方式是指所指decltype(x)
的类型,所以。并且是所指的类型,所以。x
int
decltype(y)
y
int&
如果我们避免tuple_element
,通过执行以下操作:
auto&& x = std::get<0>(__e);
auto&& y = std::get<1>(__e);
然后我们无法区分x
and y
,因为没有办法区分 whatstd::get<0>(__e)
和std::get<1>(__e)
do :两者都返回一个int&
.
这也是在上述情况和普通结构情况之间添加一致性的方法:
struct C {
int i;
int& r;
};
C& bar();
auto& [a, b] = bar();
出于结构化绑定的目的,我们希望 fora
和b
here 的行为方式与x
和y
there 相同。and这里没有引入变量,它们只是a
和的不同名称。b
__e.i
__e.r
在非参考情况下,有一个不同的场景我们无法区分:
std::tuple<int, int&&> foo();
auto [x, y] = foo();
在这里,我们目前通过以下方式解包:
auto __e = foo();
std::tuple_element_t<0, decltype(e)>& x = std::get<0>(std::move(__e));
std::tuple_element_t<1, decltype(e)>& y = std::get<1>(std::move(__e));
两个std::get
调用都返回一个int&&
,因此您无法使用auto&&
... 区分它们,但结果分别tuple_element_t
是 -int
和int&&
。这种差异也可以在正常的 struct 案例中看到。
†请注意,由于CWG 2313,实际上解包发生在一个唯一命名的变量引用中,并且绑定中指定的标识符仅引用这些对象。