webentwicklung-frage-antwort-db.com.de

Was sind einige Verwendungszwecke von decltype (auto)?

In c ++ 14 wird das decltype(auto)-Idiom eingeführt.

Normalerweise wird es verwendet, um auto -Deklarationen die Verwendung der decltype -Regeln für den angegebenen Ausdruck zu erlauben.

Auf der Suche nach Beispielen für eine "gute" Verwendung der Redewendung fallen mir nur Dinge wie die folgenden ein (von Scott Meyers ), nämlich Abzug des Rückgabetyps einer Funktion:

template<typename ContainerType, typename IndexType>                // C++14
decltype(auto) grab(ContainerType&& container, IndexType&& index)
{
  authenticateUser();
  return std::forward<ContainerType>(container)[std::forward<IndexType>(index)];
}

Gibt es andere Beispiele, in denen diese neue Sprachfunktion nützlich ist?

128

Geben Sie die Weiterleitung im generischen Code zurück

Bei nicht generischem Code können Sie, wie im ersten Beispiel, manuell auswählen, dass eine Referenz als Rückgabetyp verwendet werden soll:

auto const& Example(int const& i) 
{ 
    return i; 
}

aber in generischer Code möchten Sie einen Rückgabetyp perfekt weiterleiten können, ohne zu wissen, ob es sich um eine Referenz oder um eine Referenz handelt Wert. decltype(auto) gibt Ihnen diese Fähigkeit:

template<class Fun, class... Args>
decltype(auto) Example(Fun fun, Args&&... args) 
{ 
    return fun(std::forward<Args>(args)...); 
}

Verzögerung des Abzugs von Rückgabetypen in rekursiven Vorlagen

In this Q & A wurde vor einigen Tagen eine unendliche Rekursion während der Vorlageninstanziierung festgestellt, als der Rückgabetyp der Vorlage als decltype(iter(Int<i-1>{})) angegeben wurde. anstelle von decltype(auto).

template<int i> 
struct Int {};

constexpr auto iter(Int<0>) -> Int<0>;

template<int i>
constexpr auto iter(Int<i>) -> decltype(auto) 
{ return iter(Int<i-1>{}); }

int main() { decltype(iter(Int<10>{})) a; }

decltype(auto) wird hier verwendet, um den Abzug des Rückgabetyps zu verzögern , nachdem sich der Staub der Template-Instanziierung gelegt hat.

Andere Verwendungen

Sie können decltype(auto) auch in anderen Kontexten verwenden, z. Der Standardentwurf N3936 besagt ebenfalls

7.1.6.4 auto speci fi er [dcl.spec.auto]

1 Die Typbezeichner auto und decltype(auto) bezeichnen einen Platzhaltertyp, der später ersetzt wird, entweder durch Abzug von einem Initialisierer oder durch explizite Angabe eines Trailing-Return-Typs. Der Typspezifizierer auto wird auch verwendet, um anzuzeigen, dass ein Lambda ein generisches Lambda ist.

2 Der Platzhaltertyp kann mit einem Funktionsdeklarator in der Deklarationsspezifizierersequenz, der Typspezifizierersequenz, der Konvertierungsfunktions-ID oder dem nachfolgenden Rückgabetyp = sein in jedem Kontext, in dem ein solcher Deklarator gültig ist . Wenn der Funktionsdeklarator einen Trailing-Return-Typ (8.3.5) enthält, gibt dieser den deklarierten Return-Typ der Funktion an. Wenn der deklarierte Rückgabetyp der Funktion einen Platzhaltertyp enthält, wird der Rückgabetyp der Funktion ggf. aus den return-Anweisungen im Hauptteil der Funktion abgeleitet.

Der Entwurf enthält auch das folgende Beispiel für die Variableninitialisierung:

int i;
int&& f();
auto x3a = i;                  // decltype(x3a) is int
decltype(auto) x3d = i;        // decltype(x3d) is int
auto x4a = (i);                // decltype(x4a) is int
decltype(auto) x4d = (i);      // decltype(x4d) is int&
auto x5a = f();                // decltype(x5a) is int
decltype(auto) x5d = f();      // decltype(x5d) is int&&
auto x6a = { 1, 2 };           // decltype(x6a) is std::initializer_list<int>
decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression
auto *x7a = &i;                // decltype(x7a) is int*
decltype(auto)*x7d = &i;       // error, declared type is not plain decltype(auto)
142
TemplateRex

Zitate aus hier :

  • decltype(auto) ist in erster Linie nützlich, um den Rückgabetyp von Weiterleitungsfunktionen und ähnlichen Wrappern abzuleiten, bei denen der Typ genau „verfolgt“ werden soll. ein Ausdruck, den Sie anrufen.

  • Zum Beispiel mit den folgenden Funktionen:


   string  lookup1();
   string& lookup2();

  • In C++ 11 könnten wir die folgenden Wrapper-Funktionen schreiben, die daran denken, die Referenz des Rückgabetyps beizubehalten:

   string  look_up_a_string_1() { return lookup1(); }
   string& look_up_a_string_2() { return lookup2(); }

  • In C++ 14 können wir das automatisieren:

   decltype(auto) look_up_a_string_1() { return lookup1(); }
   decltype(auto) look_up_a_string_2() { return lookup2(); }

  • decltype(auto) ist jedoch nicht als weit verbreitetes Feature gedacht.

  • Insbesondere, obwohl es verwendet werden kann, um lokale Variablen zu deklarieren , ist dies wahrscheinlich nur ein Gegenmuster, da die Referenzierbarkeit einer lokalen Variablen nicht von dem abhängen sollte Initialisierungsausdruck.

  • Außerdem ist es wichtig, wie Sie die return-Anweisung schreiben.

  • Beispielsweise haben die beiden folgenden Funktionen unterschiedliche Rückgabetypen:


   decltype(auto) look_up_a_string_1() { auto str = lookup1(); return str; }
   decltype(auto) look_up_a_string_2() { auto str = lookup2(); return(str); }

  • Die erste gibt string zurück, die zweite gibt string& Zurück, was eine Referenz auf die lokale Variable str ist.

Aus dem Vorschlag können Sie weitere Verwendungszwecke erkennen.

26
101010