decltype(auto) hat einen wichtigen Unterschied zu auto selbst: Es berücksichtigt die Wertkategorie des Rückgabetyps.
[dcl.spec.auto]/7 schrieb:
If the placeholder is the decltype(auto) type-specifier, the declared type of the variable or return type of the function shall be the placeholder alone. The type deduced for the variable or return type is determined as described in 7.1.6.2, as though the initializer had been the operand of the decltype .
Die Regeln für decltype sagen jedoch aus, dass für Ausdrücke die keine Identifier sind, ggf. Referenzen deduziert werden - abhängig von Wertkategorie des Ausdrucks. I.e.
- Für xvalues werden Rvalue-Referenzen deduziert
- ... und für lvalues Lvalue-Referenzen.
- Bei prvalues ist es einfach der Typ.
Das ist nützlich wenn wir einen proxycall durchführen:
decltype(auto) f(auto&&... args) {
return myFunctionObject(std::forward<decltype(args)>(args)...);
}
Gibt myFunctionObject nun bspw. einen std::string& zurück, so gibt f auch einen std::string& zurück. Hätten wir hingegen auto benutzt, so gäbe f std::string zurück, es sei denn wir hätten trailing-return-types benutzt - wofür wir aber zu Faul sind.
PS:
Der trailing-return-type in
auto foo(int i) -> auto { return i + 1; }
ist zwar gültig aber völlig überflüssig. Also ja: Ist dasselbe wie ohne.
Was genau tut das "-> decltype()" dahinter, ich nehme an, es hat was mit dem returntype zutun?
Es ist der return type, aber wie bereits angedeutet verwendet man darin Dinge wie Klassenmember oder Funktionsparameter. Der Standard selbst bringt hier ein Beispiel:
[dcl.fct] schrieb:
[ Note: Typedefs and trailing-return-types are sometimes
convenient when the return type of a function is complex. For example, the function fpif above could have been declared
typedef int IFUNC(int);
IFUNC* fpif(int);
or
auto fpif(int)->int(*)(int);
A trailing-return-type is most useful for a type that would be more complicated to specify before the declarator-id:
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
rather than
template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
— end note ]