Strukturierte Bindungsreferenz mit Referenztupel
Der strukturierte Bindungsfall2 in cppreference ist etwas schwer zu verstehen. Grundsätzlich möchte ich eine Klärung dieser Situationen
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
Und wenn es ein Referenztupel für die Funktionsrückgabe gibt, wie kann ich eine Kopie mit strukturierter Bindung erstellen?
std::tuple<int&, double&> f;
auto [x, y] = f(); //But I want a copy from the reference, how?
Antworten
std::forward_as_tuple(x, y)gibt dir eine tuple<int&, double&>. Die Arten der Bindungen in der liegen int&und double&(in der gleichen Art und Weise , dass die Arten der Bindungen in tuple<int, double>sind intund double). Grundsätzlich:
auto [a, b] = std::forward_as_tuple(x, y);
auto&& [c, d] = std::forward_as_tuple(x, y);
verhält sich wie:
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));
aIst also ein rWert-Verweis auf int&und cist ein rWert-Verweis auf double&, so int&und so double&. Diese besondere Formulierung (Ich bin speziell es ein Verweis auf Referenz nennen, anstatt sie nur anrufen int&) ist notwendig , da , decltype(name)wo nameeine strukturierte Bindung gibt Ihnen die referenzierten Typ, weshalb decltype(a)Sie geben würde int&.
Das Obige zeigt auch den Unterschied zwischen dem [a, b]und dem [c, d]Fall: Die autovs- auto&&Deklaration gilt für das unbenannte Objekt, das wir destrukturieren. Die Bindungen selbst sind davon nicht betroffen † .
Dieser Fall:
auto&& [e, f] = std::tuple{x, y};
Gibt keine Referenzen an, da es entpackt wird für:
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 eist ein rvalue Bezug auf int, was bedeutet , decltype(e)ist int, nicht int&.
Und wenn es ein Referenztupel für die Funktionsrückgabe gibt, wie kann ich eine Kopie mit strukturierter Bindung erstellen?
Sie können keine Kopie mit strukturierten Bindungen erstellen. Bei strukturierten Bindungen geht es ausschließlich um die Destrukturierung eines Objekts, es geht überhaupt nicht darum, etwas zu ändern. Wenn Sie eine Kopie erstellen möchten, müssen Sie dies manuell tun:
std::tuple<int&, double&> f = /* ... */;
std::tuple<int, double> actual_copy = f;
auto& [x, y] = actual_copy;
† Im obigen Fall, da das zugrunde liegende Objekt, das zerstört wird, eine l-Wert-Referenz ( auto&) ist, werden die Bindungen selbst technisch zu l-Wert-Verweisen auf irgendetwas anstatt zu r-Wert-Verweisen auf irgendetwas - obwohl ich nicht sicher bin, ob dies tatsächlich eine sinnvolle Unterscheidung ist .
Wie kann ich eine Kopie mit strukturierter Bindung erstellen, wenn ein Referenztupel für die Funktionsrückgabe vorhanden ist?
Vielleicht wäre eine Hilfsfunktion wie die folgende nützlich:
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());