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

Dav*_*one 13 c++ c++17 structured-bindings

最新草稿结构化绑定提案(在其上的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>()));
};
Run Code Online (Sandbox Code Playgroud)

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

Bar*_*rry 6

考虑一下案例:

std::tuple<int, int&>& foo();
auto& [x, y] = foo();
Run Code Online (Sandbox Code Playgroud)

什么是decltype(x)什么decltype(y)?语言功能的目标是x只是另一个名称,foo().__0并且y是另一个名称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);
Run Code Online (Sandbox Code Playgroud)

而规则的工作,从而decltype(x)是它的类型x 是指,所以int.并且decltype(y)y 的类型,所以int&.

如果我们避免tuple_element,通过这样做:

auto&& x = std::get<0>(__e);
auto&& y = std::get<1>(__e);
Run Code Online (Sandbox Code Playgroud)

然后我们无法区分xy,因为没有办法区分什么std::get<0>(__e)std::get<1>(__e)做什么:两者都给予回报int&.

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

struct C {
    int i;
    int& r;
};
C& bar();
auto& [a, b] = bar();
Run Code Online (Sandbox Code Playgroud)

我们希望,对于结构化绑定的目的,a并且b这里有同样的表现方式xy存在.而ab此不引入变量,他们只是不同的名称__e.i__e.r.


在非参考案例中,我们无法区分不同的情况:

std::tuple<int, int&&> foo();
auto [x, y] = foo();
Run Code Online (Sandbox Code Playgroud)

在这里,我们目前通过以下方式解压:

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));
Run Code Online (Sandbox Code Playgroud)

这两个std::get调用返回的int&&,所以你可以在它们之间使用不区分auto&&......但结果tuple_element_t-是不同的int,并int&&分别.这种差异可以在普通的结构案例中看到.


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