it-swarm.com.de

std :: remove_reference erklärt?

Ich sah mögliche Implementierungen für std::remove_reference wie unten

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};   

Warum gibt es Spezialisierungen für lvalue und rvalue reference? Reicht die allgemeine Vorlage nicht aus und wird der Verweis entfernt? Ich bin hier verwirrt, weil ich in der Spezialisierung T& oder T&&, wenn ich versuche, ::type zu verwenden, immer noch T& oder T&& bekomme, oder?

Können Sie erklären, warum wir in move auf remove_reference<t>::type&& umsteigen? (Liegt es daran, dass der Parameter so benannt ist, dass er in der move-Funktion als l-Wert behandelt wird?).

Könnten Sie auch einen Weg aufzeigen, wie ich herausfinden und ausdrucken kann, welcher Typ vorliegt? Wenn es sich beispielsweise um eine rvalue vom Typ int handelt, sollte ich dann in der Lage sein, auszudrucken, dass der int&& übergeben wurde. (Ich habe std::is_same verwendet, um zu überprüfen, aber manuell.)

Vielen Dank für Ihre Zeit.

26
Koushik Shetty

warum gibt es spezialisierungen für lvalue und rvalue reference?

Wenn nur die primäre Vorlage vorhanden war, tun Sie Folgendes:

remove_reference<int&>::type

Würde dir geben:

int&

Und dabei:

remove_reference<int&&>::type

Würde dir geben:

int&&

Welches ist nicht was Sie wollen. Mit den Spezialisierungen für lvalue-Referenzen und rvalue-Referenzen können Sie den & bzw. den && aus dem Typargument entfernen, das Sie übergeben.

Zum Beispiel, wenn Sie tun:

remove_reference<int&&>

Der Typ int&& entspricht dem in der Spezialisierung T&& angegebenen Muster, wobei Tint ist. Da die Spezialisierung den Typ-Alias ​​type als T definiert (in diesem Fall int), tun Sie Folgendes:

remove_reference<int&&>::type

Gibt dir int.

können Sie erklären, warum wir in moveremove_reference<t>::type&& umgewandelt haben?

Das liegt daran, dass wenn move() wie folgt definiert wäre:

    template<typename T>
    T&& move(T&& t) { ... }
//  ^^^
//  Resolves to X& if T is X& (which is the case if the input has type X
//  and is an lvalue)

Der Rückgabetyp ist dann X&, wenn das Argument von move() ein Wert vom Typ X ist (so genannte "Universalreferenzen"). Wir wollen sicherstellen, dass der Rückgabetyp immer eine Wertreferenz ist.

Der Zweck von move() ist es, Ihnen einen Wert zurückzugeben, unabhängig davon, was Sie bei der Eingabe übergeben. Da ein Funktionsaufruf für eine Funktion, deren Rückgabetyp eine R-Wert-Referenz ist, ein R-Wert ist, möchten wir, dass move() immer eine R-Wert-Referenz zurückgibt.

Deshalb machen wir remove_reference<T>::type&&, weil das Anhängen von && an einen Nicht-Referenztyp immer garantiert einen r-Wert-Referenztyp ergibt.

Könnten Sie auch einen Weg aufzeigen, auf dem ich herausfinden und ausdrucken kann, um welchen Typ es sich handelt?

Ich bin mir nicht sicher, was Sie hier mit "Drucken" meinen. Es gibt keine übertragbare Möglichkeit, den Namen eines Typs in einen String umzuwandeln (unabhängig davon, wie Sie diesen Typ erhalten).

Wenn Sie sicherstellen möchten, dass ein Wert übergeben wurde, können Sie eine statische Aussage wie die folgende verwenden:

#include <type_traits>

template<typename T>
void foo(T&&)
{
    static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!");
    // ...
}

Dies beruht auf der Tatsache, dass beim Übergeben eines Werts vom Typ XT als X& abgeleitet wird.

Sie können auch eine äquivalente SFINAE-Einschränkung verwenden, wenn Sie nur einen Substitutionsfehler erzeugen möchten:

#include <type_traits>

template<typename T, typename std::enable_if<
    !std::is_reference<T>::value>::type* = nullptr>
void foo(T&&)
{
    // ...
}
37
Andy Prowl

Wenn Sie einen Typ als Vorlagenparameter behandeln, sucht der Compiler nach der "spezialisiertesten" Spezialisierung. Wenn Sie ein int && an diese Vorlage übergeben, verwendet der Compiler die Version remove_reference<T&&>. Allgemeine Spezialisierung gibt dir nicht das, was du willst - wenn du int&& an die allgemeine Spezialisierung übergibst, wird Typ int&& sein

Wenn Sie den Typ drucken möchten, verwenden Sie typeid(some_type).name()

0
Evgeny Eltishev