Si vous avez besoin du type de quelque chose qui ne ressemble pas à un appel de fonction, std::result_of
cela ne s'applique tout simplement pas. decltype()
peut vous donner le type de n'importe quelle expression.
Si nous nous limitons aux différentes manières de déterminer le type de retour d'un appel de fonction (entre std::result_of_t<F(Args...)>
et decltype(std::declval<F>()(std::declval<Args>()...)
), alors il y a une différence.
std::result_of<F(Args...)
est défini comme:
Si l'expression
INVOKE (declval<Fn>(), declval<ArgTypes>()...)
est bien formée lorsqu'elle est traitée comme un opérande non évalué (clause 5), le type typedef membre doit nommer le typedecltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
sinon, il n'y aura pas de type de membre.
La différence entre result_of<F(Args..)>::type
et decltype(std::declval<F>()(std::declval<Args>()...)
est tout à propos de cela INVOKE
. L'utilisation de declval
/ decltype
directement, en plus d'être un peu plus longue à taper, n'est valide que si elle F
est directement appelable (un type d'objet fonction ou une fonction ou un pointeur de fonction).result_of
prend également en charge les pointeurs vers les fonctions des membres et les pointeurs vers les données des membres.
Initialement, utiliser declval
/ decltype
garanti une expression compatible SFINAE, alors que cela std::result_of
pourrait vous donner une erreur matérielle au lieu d'un échec de déduction. Cela a été corrigé en C ++ 14: std::result_of
doit maintenant être compatible avec SFINAE (grâce à ce papier ).
Donc, sur un compilateur C ++ 14 conforme, std::result_of_t<F(Args...)>
c'est strictement supérieur. C'est plus clair, plus court et correctement † prend en charge plus de F
s ‡ .
† À moins que vous ne l'utilisiez dans un contexte où vous ne souhaitez pas autoriser les pointeurs vers les membres, cela
std::result_of_t
réussirait dans un cas où vous pourriez souhaiter qu'il échoue.
‡ Sauf exceptions. Bien qu'il prenne en charge les pointeurs vers les membres, result_of
ne fonctionnera pas si vous essayez d'instancier un type-id non valide . Celles-ci incluraient une fonction renvoyant une fonction ou prenant des types abstraits par valeur. Ex.:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
L'utilisation correcte aurait été result_of_t<F&()>
, mais c'est un détail dont vous n'avez pas à vous souvenir decltype
.
decltype
sache, c'est plus laid mais aussi plus puissant.result_of
ne peut être utilisé que pour les types appelables et nécessite des types comme arguments. Par exemple, vous ne pouvez pas utiliserresult_of
ici:template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );
si les arguments peuvent être des types arithmétiques (il n'y a pas de fonctionF
telle que vous pouvez définirF(T,U)
pour représentert+u
. Pour les types définis par l'utilisateur, vous pouvez. De la même manière (je n'ai pas vraiment joué avec) j'imagine que les appels aux méthodes membres peuvent être difficiles à faireresult_of
sans utiliser de liants ou de lambdas