Wenn Sie den Typ von etwas benötigen, das nicht wie ein Funktionsaufruf ist, std::result_oftrifft dies einfach nicht zu. decltype()kann Ihnen den Typ eines beliebigen Ausdrucks geben.
Wenn wir uns nur auf die verschiedenen Methoden zur Bestimmung des Rückgabetyps eines Funktionsaufrufs (zwischen std::result_of_t<F(Args...)>und decltype(std::declval<F>()(std::declval<Args>()...)) beschränken, gibt es einen Unterschied.
std::result_of<F(Args...) ist definiert als:
Wenn der Ausdruck
INVOKE (declval<Fn>(), declval<ArgTypes>()...)gut formuliert ist, wenn er als nicht bewerteter Operand behandelt wird (Abschnitt 5), benennt der Typ typedef des Mitglieds den Typ, decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
andernfalls gibt es keinen Elementtyp .
Der Unterschied zwischen result_of<F(Args..)>::typeund decltype(std::declval<F>()(std::declval<Args>()...)ist alles darüber INVOKE. Die Verwendung von declval/ decltypedirekt ist nicht nur etwas länger zu tippen, sondern auch nur gültig, wenn sie Fdirekt aufrufbar ist (ein Funktionsobjekttyp oder eine Funktion oder ein Funktionszeiger). result_ofunterstützt zusätzlich Zeiger auf Mitgliederfunktionen und Zeiger auf Mitgliedsdaten.
Anfänglich wird ein SFINAE-freundlicher Ausdruck verwendet declval/ decltypegarantiert, während std::result_ofdies zu einem schweren Fehler anstelle eines Abzugsfehlers führen kann. std::result_ofDies wurde in C ++ 14 korrigiert: Es muss jetzt SFINAE-freundlich sein (dank dieses Dokuments ).
Also auf einem konformen C ++ 14-Compiler std::result_of_t<F(Args...)>ist es absolut überlegen. Es ist klarer, kürzer und unterstützt † mehr Fs ‡ .
† Es sei denn, Sie verwenden es in einem Kontext, in dem Sie keine Zeiger auf Mitglieder zulassen möchten. Dies
std::result_of_twäre also in einem Fall erfolgreich, in dem Sie möglicherweise möchten, dass es fehlschlägt.
‡ Mit Ausnahmen. Es unterstützt zwar Zeiger auf Mitglieder, result_offunktioniert jedoch nicht, wenn Sie versuchen, eine ungültige Typ-ID zu instanziieren . Dazu gehört eine Funktion, die eine Funktion zurückgibt oder abstrakte Typen nach Wert nimmt. Ex.:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
Die richtige Verwendung wäre gewesen result_of_t<F&()>, aber das ist ein Detail, an das Sie sich nicht erinnern müssen decltype.
decltypeweiß, ist es hässlicher, aber auch mächtiger.result_ofkann nur für aufrufbare Typen verwendet werden und erfordert Typen als Argumente. Zum Beispiel können Sieresult_ofhier nicht verwenden :template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );Wenn die Argumente arithmetische Typen sein können (es gibt keine FunktionF, die Sie definieren können, umF(T,U)sie darzustellent+u. Für benutzerdefinierte Typen könnten Sie. Auf die gleiche Weise (ich habe nicht wirklich damit gespielt) stelle ich mir vor Das Aufrufen von Mitgliedsmethoden könnte schwierig sein,result_ofohne Bindemittel oder Lambdas zu verwenden