带有引用元组的结构化绑定引用

Structured binding reference with tuple of reference

Structured binding Case2 in cppreference有点难懂。基本上,我想澄清这些情况

int x = 1;
double y = 2.0;
auto [a, b] = std::forward_as_tuple(x, y);   //a, b are both reference, why?
auto&& [c, d] = std::forward_as_tuple(x, y); //What's the difference of this and above?
auto&& [e, f] = std::tuple{x, y};  //why are NOT e, f rvalue references? Resharper shows them as value type not reference type

如果有一些函数 return 引用元组,我如何使用结构化绑定制作副本?

std::tuple<int&, double&> f;
auto [x, y] = f(); //But I want a copy from the reference, how?

std::forward_as_tuple(x, y) 给你一个 tuple<int&, double&>。绑定到的类型是 int&double&(与绑定到 tuple<int, double> 的类型是 intdouble 的方式相同)。基本上:

auto [a, b] = std::forward_as_tuple(x, y);
auto&& [c, d] = std::forward_as_tuple(x, y);

表现得好像:

auto __e = std::forward_as_tuple(x, y);
using __E = remove_reference_t<decltype(__e)>;
tuple_element_t<0, __E>&& a = std::get<0>(std::move(__e));
tuple_element_t<1, __E>&& b = std::get<1>(std::move(__e));

auto&& __f = std::forward_as_tuple(x, y);
using __F = remove_reference_t<decltype(__f)>;
tuple_element_t<0, F>&& c = std::get<0>(std::move(__f));
tuple_element_t<1, F>&& d = std::get<1>(std::move(__f));

所以a是对int&的右值引用,c是对double&的右值引用,所以int&double&分别。这个特殊的公式(我特别称它为引用的引用,而不是仅仅称它为 int&)是必要的,因为 decltype(name) 其中 name 是一个结构化绑定给你 referenced 类型,这就是为什么 decltype(a) 会给你 int&.

上面还显示了 [a, b][c, d] 情况之间的区别:autoauto&& 声明适用于我们正在解构的未命名对象.它不会影响绑定本身.

本案例:

auto&& [e, f] = std::tuple{x, y};

不提供参考,因为它解压到:

auto&& __g = std::tuple{x, y};
using __G = remove_reference_t<decltype(__g)>;
tuple_element_t<0, G>&& e = std::get<0>(std::move(__g));
tuple_element_t<1, G>&& f = std::get<1>(std::move(__g));

所以e是对int的右值引用,这意味着decltype(e)int,而不是int&


And if there is some function return tuple of reference, how can I make a copy using structured binding?

您不能使用结构化绑定制作副本。结构化绑定 只是 关于对象的解构,它根本不是关于改变任何东西。如果要复制,则必须手动执行:

std::tuple<int&, double&> f = /* ... */;
std::tuple<int, double> actual_copy = f;
auto& [x, y] = actual_copy; 

在上面的例子中,因为被解构的底层对象是一个左值引用(auto&),这在技术上使绑定本身成为对任何东西的左值引用对任何东西的右值引用——虽然我不确定这是否真的是一个有意义的区别。

if there is some function return tuple of reference, how can I make a copy using structured binding?

也许像下面这样的辅助函数会很有用:

template <class Tuple, size_t... indices>
constexpr auto
tuple_copy_impl(const Tuple& tuple, std::index_sequence<indices...>) {
   return std::tuple{std::get<indices>(tuple)...};
}

template <class Tuple>
constexpr auto
tuple_copy(const Tuple& tuple) {
    constexpr auto s = std::tuple_size_v<Tuple>;
    using I = std::make_index_sequence<s>;
    return tuple_copy_impl<Tuple>(tuple, I{});
}

auto [x, y] = tuple_copy(f());