std::forward_as_tuple(x, y)
给你一个tuple<int&, double&>
。绑定的类型是int&
and double&
(与绑定类型相同的方式tuple<int, double>
are int
and 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));
So a
是一个右值引用int&
and c
是一个右值引用double&
, so int&
and double&
分别。这个特殊的表述(我特意将其称为对参考的引用,而不是仅仅将其称为int&
)是必要的,因为decltype(name)
where name
是一个结构化的绑定给你引用的类型,这就是为什么decltype(a)
会给你int&
.
The above also shows the difference between the [a, b]
and the [c, d]
case: the auto
vs auto&&
declaration applies to the unnamed object that we're destructuring. It does not affect the bindings themselves†.
这个案例:
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));
So e
是一个右值引用int
, 意思是decltype(e)
is int
, not int&
.
如果有一些函数返回引用元组,我如何使用结构化绑定来制作副本?
您无法使用结构化绑定来制作副本。结构化绑定是solely关于解构一个对象,它根本不是改变任何东西。如果您想制作副本,则必须手动执行此操作:
std::tuple<int&, double&> f = /* ... */;
std::tuple<int, double> actual_copy = f;
auto& [x, y] = actual_copy;
†In the above case, because the underlying object being destructured is an lvalue reference (auto&
), this technically makes the bindings themselves lvalue references to whatever instead of rvalue references to whatever -- although I'm not sure if this is actually a meaningful distinction.