14

结构化绑定提案的最新草案(C++17 特性基于该草案)需要std::tuple_size、成员getstd::get、和std::tuple_element以前的草稿只需要std::tuple_size和 成员getstd::get。据我所知,没有关于添加这个的讨论,它只是出现在最终草案中。tuple_element考虑到我相信它可以普遍实施,是否有令人信服的理由要求专业化

template<std::size_t index, typename T>
struct tuple_element {
    using type = decltype(std::get<index>(std::declval<T>()));
};

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

4

1 回答 1

6

考虑以下情况:

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

什么是decltype(x)和什么是decltype(y)?语言功能的目标是x成为foo().__0y的另一个名称foo().__1,这意味着它们应该分别是intint&。正如今天所指定的,这将解压缩为

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();

出于结构化绑定的目的,我们希望 forabhere 的行为方式与xythere 相同。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是 -intint&&。这种差异可以在正常的 struct 案例中看到。


请注意,由于CWG 2313,实际上解包发生在一个唯一命名的变量引用中,并且绑定中指定的标识符仅引用这些对象。

于 2018-04-27T16:00:59.790 回答