考虑以下情况:
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 intdecltype(y)y int&
如果我们避免tuple_element,通过执行以下操作:
auto&& x = std::get<0>(__e);
auto&& y = std::get<1>(__e);
然后我们无法区分xand y,因为没有办法区分 whatstd::get<0>(__e)和std::get<1>(__e)do :两者都返回一个int&.
这也是在上述情况和普通结构情况之间添加一致性的方法:
struct C {
int i;
int& r;
};
C& bar();
auto& [a, b] = bar();
出于结构化绑定的目的,我们希望 fora和bhere 的行为方式与x和ythere 相同。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,实际上解包发生在一个唯一命名的变量引用中,并且绑定中指定的标识符仅引用这些对象。