Was sind einige Verwendungen von decltype(auto)?

Lesezeit: 7 Minuten

Was sind einige Verwendungen von decltypeauto
Nikos Athanasiou

In c++14 die decltype(auto) Redewendung eingeführt.

Typischerweise ist seine Verwendung zu ermöglichen auto Erklärungen zur Verwendung der decltype Regeln für den gegebenen Ausdruck.

Bei der Suche nach Beispielen für eine „gute“ Verwendung der Redewendung fallen mir nur Dinge wie die folgenden ein (by Scott Meyers), nämlich für die Rückgabetypableitung 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 weitere Beispiele, bei denen diese neue Sprachfunktion nützlich ist?

  • Dieser Beitrag schlägt im Grunde vor, diese Redewendung zu vermeiden, da Sie Ihrem Compiler stackoverflow.com/a/20092875/2485710 weniger Optionen zur Optimierung geben, wenn Sie sie verwenden

    – Benutzer2485710

    8. Juni 2014 um 19:27 Uhr

  • Ich habe einmal verwendet decltype(auto) für etwas ähnliches template<class U, V> decltype(auto) first(std::pair<U, V>& p) { return p.first; }obwohl mir dann klar wurde, dass ich es verwenden musste return (p.first); was überraschenderweise funktioniert (aber IIRC ist sogar beabsichtigt).

    – dyp

    8. Juni 2014 um 19:50 Uhr

  • @ user2485710 Ich bin mir nicht sicher, ob es speziell um Optimierung geht, eher um das Potenzial für Unfälle, wenn decltype(auto) kann dazu führen, dass etwas wider Erwarten in das deklarierte Objekt kopiert/verschoben wird.

    – Unterstrich_d

    17. April 2016 um 17:45 Uhr

  • In dem Beispiel, das Sie oben geben, wenn container ist eigentlich ein rvalue. Ich denke, die Verwendung von decltype(auto) kann zu versehentlichen Verweisen auf Dangles führen. Sie können jedoch den Werttyp von ContainerType zurückgeben, und das Kopieren von Ellision sollte Ihnen dasselbe wie decltype (auto) geben, aber sicher als Referenz verwendet werden godbolt.org/z/GsYjxs

    – Steve_Corrin

    6. Oktober 2020 um 18:37 Uhr


  • Ja, hier ist ein weiteres Beispiel, bei dem der interne Wert des Containers zerstört wird, aber wir bitten um einen Verweis darauf von der Funktion godbolt.org/z/7jE5Me

    – Steve_Corrin

    7. Oktober 2020 um 18:26 Uhr

1646728214 498 Was sind einige Verwendungen von decltypeauto
TemplateRex

Rückgabetypweiterleitung in generischem Code

Für nicht generischen Code, wie das erste Beispiel, das Sie gegeben haben, können Sie manuell auswählen, um eine Referenz als Rückgabetyp zu erhalten:

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

aber in generischer Code du willst es können leiten Sie einen Rückgabetyp perfekt weiter ohne zu wissen, ob es sich um eine Referenz oder einen Wert handelt. 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 Rückgabetypabzugs in rekursiven Vorlagen

Im diese Fragen und Antworten Vor ein paar Tagen wurde eine unendliche Rekursion während der Template-Instanziierung festgestellt, als der Rückgabetyp des Templates als angegeben wurde decltype(iter(Int<i-1>{})) anstatt 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) ist hier gewohnt Verzögern Sie den Rückgabetypabzug nachdem sich der Staub der Template-Instanziierung gelegt hat.

Andere Verwendungen

Sie können auch verwenden decltype(auto) in anderen Zusammenhängen, z. B. dem Normentwurf N3936 auch Staaten

7.1.6.4 Autospezifizierer [dcl.spec.auto]

1 Die auto und decltype(auto) Typbezeichner bezeichnen einen Platzhaltertyp, der später ersetzt wird, entweder durch Ableitung von einem Initialisierer oder durch explizite Angabe mit einem nachgestellten Rückgabetyp. Die auto type-specifier wird auch verwendet, um anzuzeigen, dass ein Lambda ein generisches Lambda ist.

2 Der Platzhaltertyp erscheinen kann mit einem Funktionsdeklarator in decl-specifier-seq, type-specifier-seq, conversion-function-id oder trailing-return-type, in jedem Kontext, in dem ein solcher Deklarator gültig ist. Wenn der Funktionsdeklarator einen Trailing-Return-Type (8.3.5) enthält, gibt dieser den deklarierten Rückgabetyp der Funktion an. Wenn der deklarierte Rückgabetyp der Funktion einen Platzhaltertyp enthält, wird der Rückgabetyp der Funktion gegebenenfalls aus Rückgabeanweisungen im Hauptteil der Funktion abgeleitet.

Der Entwurf enthält auch dieses Beispiel der 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)

  • Ist das unterschiedliche Verhalten von (i) vs i etwas Neues in C++14?

    – Danvil

    9. Juni 2014 um 0:37 Uhr


  • @ Danvil decltype(expr) und decltype((expr)) bereits in C++11 anders sind, verallgemeinert dies dieses Verhalten.

    – TemplateRex

    9. Juni 2014 um 5:33 Uhr


  • Ich habe gerade erfahren, dass es sich wie eine schreckliche Designentscheidung anfühlt … der syntaktischen Bedeutung von Klammern eine punktuelle Nuance hinzuzufügen.

    – Kähler

    2. Januar 2017 um 19:15 Uhr

  • Das Beispiel, das immer diesen Ekel hervorruft, ist die Einzeiler-Datei-zu-String-Syntax (auch in diesem Link erwähnt). Jeder Teil davon scheint rückständig. Möglicherweise erwarten Sie überhaupt keine Mehrdeutigkeit und entfernen zwangsläufig redundante Klammern aus einem Beispiel. Sie würden erwarten, dass Mehrdeutigkeiten durch ein Eliminierungsverfahren gemäß SFINAE gelöst werden, aber andere potenzielle Kandidaten als die Erklärung werden im Voraus eliminiert (SFistAE); und frustriert könnten Sie weitermachen, sobald es kompiliert, denken, dass die willkürlichen Klammern Mehrdeutigkeiten lösen, aber sie einführen es. Am ärgerlichsten für CS101-Professoren, stelle ich mir vor.

    – Johannes P

    1. Januar 2018 um 3:47 Uhr

  • @TemplateRex: Über das Verzögern der Auflösung des Rückgabetyps in der referenzierten Frage: Soweit ich sehe, in der konkretes Szenarioeine einfache auto hätte den Job genauso gut gemacht, da das Ergebnis sowieso als Wert zurückgegeben wird … Oder habe ich etwas übersehen?

    – Aconcagua

    18. Januar 2018 um 17:30 Uhr

Was sind einige Verwendungen von decltypeauto
101010

Zitieren von Sachen aus Hier:

  • decltype(auto) ist in erster Linie nützlich für Ableitung des Rückgabetyps von Weiterleitungsfunktionen und ähnlichen Wrappernwo Sie möchten, dass der Typ einen Ausdruck, den Sie aufrufen, genau „verfolgt“.

  • 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(); }

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

  • Insbesondere, obwohl es verwendet werden kann Deklarieren Sie lokale Variablenist dies wahrscheinlich nur ein Antimuster, da die Referenz einer lokalen Variablen nicht vom Initialisierungsausdruck abhängen sollte.

  • Außerdem ist es empfindlich, 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); }

  • Der erste kehrt zurück stringdie zweite kehrt zurück string&was ein Verweis auf die lokale Variable ist str.

Von dem Vorschlag Sie können weitere Verwendungszwecke sehen.

  • Warum nicht einfach verwenden auto für Rücksendung?

    – BЈовић

    1. Juli 2014 um 14:08 Uhr

  • @BЈовић könnte mit verallgemeinertem Rückgabetypabzug arbeiten (dh auto return), aber das OP fragte ausdrücklich nach Verwendungen von decltype(auto).

    – 101010

    1. Juli 2014 um 19:52 Uhr


  • Die Frage ist trotzdem aktuell. Was wäre der Rückgabetyp? auto lookup_a_string() { ... } ? Ist es immer ein Nicht-Referenztyp? Und deshalb auto lookup_a_string() ->decltype(auto) { ... } wird benötigt, um zu erzwingen, dass Referenzen (in einigen Fällen) zurückgegeben werden können?

    – Aaron McDaid

    7. August 2015 um 9:57 Uhr


  • @AaronMcDaid Selbstbehalt auto ist in Bezug auf die Wertübergabevorlage definiert, also ja, es kann keine Referenz sein. Warten Sie mal auto kann natürlich alles sein, einschließlich einer Referenz.

    – Neugieriger

    16. August 2015 um 0:20 Uhr

  • Ein weiteres erwähnenswertes Beispiel ist die Rückgabe eines Elements von a std::vector. Sagen Sie, Sie haben template<typename T> struct S { auto & operator[](std::size_t i) { return v[i]; } std::vector<T> v; }. Dann S<bool>::operator[] wird aufgrund der Spezialisierung von eine baumelnde Referenz zurückgeben std::vector<bool>. Änderung des Rückgabetyps in decltype(auto) umgeht dieses Problem.

    – Xoph

    30. Mai 2018 um 14:11 Uhr

973420cookie-checkWas sind einige Verwendungen von decltype(auto)?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy