Wenn Sie den Typ von etwas benötigen, das nicht wie ein Funktionsaufruf ist, std::result_of
trifft 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..)>::type
und decltype(std::declval<F>()(std::declval<Args>()...)
ist alles darüber INVOKE
. Die Verwendung von declval
/ decltype
direkt ist nicht nur etwas länger zu tippen, sondern auch nur gültig, wenn sie F
direkt aufrufbar ist (ein Funktionsobjekttyp oder eine Funktion oder ein Funktionszeiger). result_of
unterstützt zusätzlich Zeiger auf Mitgliederfunktionen und Zeiger auf Mitgliedsdaten.
Anfänglich wird ein SFINAE-freundlicher Ausdruck verwendet declval
/ decltype
garantiert, während std::result_of
dies zu einem schweren Fehler anstelle eines Abzugsfehlers führen kann. std::result_of
Dies 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 F
s ‡ .
† Es sei denn, Sie verwenden es in einem Kontext, in dem Sie keine Zeiger auf Mitglieder zulassen möchten. Dies
std::result_of_t
wä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_of
funktioniert 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
.
decltype
weiß, ist es hässlicher, aber auch mächtiger.result_of
kann nur für aufrufbare Typen verwendet werden und erfordert Typen als Argumente. Zum Beispiel können Sieresult_of
hier 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_of
ohne Bindemittel oder Lambdas zu verwenden