most recent draft结构化绑定(bind)提案(C++17 特性所基于)需要 std::tuple_size
、成员 get
或 std::get
和 std::tuple_element
。 Previous drafts只需要 std::tuple_size
和成员 get
或 std::get
。据我所知,没有关于添加这个的讨论,它只是出现在最终草案中。考虑到我相信它通常可以实现为
tuple_element
特化
template<std::size_t index, typename T>
struct tuple_element {
using type = decltype(std::get<index>(std::declval<T>()));
};
有人知道为什么要添加这个要求吗?
最佳答案
考虑案例:
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)
做:都回馈int&
.
这也是增加上述case和普通struct case一致性的方法:
struct C {
int i;
int& r;
};
C& bar();
auto& [a, b] = bar();
出于结构化绑定(bind)的目的,我们希望 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&&
区分它们...但是 tuple_element_t
的结果不同 - int
和 int&&
, 分别。这种差异也可以在普通的 struct 案例中看到。
†请注意,由于 CWG 2313 ,实际上解包发生在一个唯一命名的变量引用中,绑定(bind)中指定的标识符只是引用这些对象。
关于c++ - 为什么结构化绑定(bind)依赖于 tuple_element?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50064922/