结构化绑定提案的most recent draft(C ++ 17功能所基于的)需要std::tuple_size
,成员get
或std::get
以及{{1 }}。 Previous drafts仅需要std::tuple_element
和成员std::tuple_size
或get
。据我所知,没有讨论增加这一点,它只是出现在最终草案中。是否有令人信服的理由要求std::get
专业化,考虑到我认为它可以一般实施为
tuple_element
有谁知道为什么要添加此要求?
答案 0 :(得分:6)
考虑这个案例:
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
和y
,因为无法区分std::get<0>(__e)
和std::get<1>(__e)
做什么:两者都回馈{{ 1}}。
这也是在上述案例和普通结构案例之间增加一致性的方法:
int&
出于结构化绑定的目的,我们希望此处struct C {
int i;
int& r;
};
C& bar();
auto& [a, b] = bar();
和a
的行为方式与b
和x
相同。 y
和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&&
的结果不同 - {{1分别是}和tuple_element_t
。这种差异也可以用普通的结构案例来看待。
†请注意,由于CWG 2313,实际上解包发生在一个唯一命名的变量引用中,并且绑定中指定的标识符只引用那些对象。