Rückgabetypweiterleitung im generischen Code
Für nicht generischen Code, wie das erste Beispiel, das Sie angegeben haben, können Sie manuell auswählen, um eine Referenz als Rückgabetyp zu erhalten:
auto const& Example(int const& i)
{
return i;
}
Im generischen Code möchten Sie jedoch in der Lage sein, einen Rückgabetyp perfekt weiterzuleiten, 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ögern des Rückzugs vom Rückgabetyp in rekursiven Vorlagen
In diesen Fragen und Antworten vor einigen Tagen wurde während der Vorlageninstanziierung eine unendliche Rekursion festgestellt, wenn der Rückgabetyp der Vorlage als decltype(iter(Int<i-1>{}))
anstelle von angegeben wurde 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 Schabloneninstanziierung gelegt hat.
Andere Verwendungen
Sie können auch decltype(auto)
in anderen Kontexten verwenden, z. B. im Entwurf des Standards N3936 auch Staaten
7.1.6.4 Auto Speci fi er [dcl.spec.auto]
1 Die auto
und decltype(auto)
-Typspezifizierer bezeichnen einen Platzhaltertyp, der später ersetzt wird, entweder durch Abzug von einem Initialisierer oder durch explizite Angabe mit einem Trailing-Return-Typ. Dasauto
Typspezifizierer wird auch verwendet, um anzuzeigen, dass ein Lambda ein generisches Lambda ist.
2 Der Platzhaltertyp kann mit einem Funktionsdeklarator in der Deklarationsspezifizierer-Sequenz, der Typspezifizierer-Sequenz, der Konvertierungsfunktions-ID oder dem nachfolgenden Rückgabetyp in jedem Kontext angezeigt werden, in dem ein solcher Deklarator gültig ist . Wenn der Funktionsdeklarator einen Trailing-Return-Typ (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 den Rückgabeanweisungen im Hauptteil der Funktion abgeleitet.
Der Entwurf enthält auch dieses 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)