为什么结构化绑定依赖于tuple_element?

时间:2018-04-27 14:47:20

标签: c++ c++17 structured-bindings

结构化绑定提案的most recent draft(C ++ 17功能所基于的)需要std::tuple_size,成员getstd::get以及{{1 }}。 Previous drafts仅需要std::tuple_element和成员std::tuple_sizeget。据我所知,没有讨论增加这一点,它只是出现在最终草案中。是否有令人信服的理由要求std::get专业化,考虑到我认为它可以一般实施为

tuple_element

有谁知道为什么要添加此要求?

1 个答案:

答案 0 :(得分:6)

考虑这个案例:

std::tuple<int, int&>& foo();
auto& [x, y] = foo();

什么是decltype(x),什么是decltype(y)?语言功能的目标是x只是foo().__0的另一个名称,yfoo().__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);

然后我们无法区分xy,因为无法区分std::get<0>(__e)std::get<1>(__e)做什么:两者都回馈{{ 1}}。

这也是在上述案例和普通结构案例之间增加一致性的方法:

int&

出于结构化绑定的目的,我们希望此处struct C { int i; int& r; }; C& bar(); auto& [a, b] = bar(); a的行为方式与bx相同。 ya这里没有引入变量,它们只是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,实际上解包发生在一个唯一命名的变量引用中,并且绑定中指定的标识符只引用那些对象。