cppreference中的结构化绑定Case2有点难以理解。基本上,我想澄清这些情况
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
如果存在引用的函数返回元组,如何使用结构化绑定进行复制?
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>
的类型为int
和double
相同(。基本上:
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
是结构化绑定,它给了你引用的类型,这就是为什么decltype(a)
会给你int&
。
上面还显示了[a, b]
和[c, d]
情况之间的区别:auto
和auto&&
声明适用于我们正在销毁的未命名对象。它不会影响绑定本身†。
本例:
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&
。
如果有引用的函数返回元组,我如何使用结构化绑定进行复制?
您无法使用结构化绑定进行复制。结构化绑定只是关于销毁对象,而不是更改任何内容。如果你想复制,你必须手动完成:
std::tuple<int&, double&> f = /* ... */;
std::tuple<int, double> actual_copy = f;
auto& [x, y] = actual_copy;
†在上述情况下,因为被破坏的底层对象是一个左值引用(auto&
(,所以从技术上讲,这使得绑定本身对任何东西都是左值引用,而不是对任何东西的右值引用——尽管我不确定这是否真的是一个有意义的区别。
如果存在引用的函数返回元组,我如何使用结构化绑定进行复制?
也许下面这样的辅助函数会很有用:
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());