J'ai du mal à comprendre la nécessité de std::result_of
C ++ 0x. Si j'ai bien compris, result_of
est utilisé pour obtenir le type résultant de l'appel d'un objet fonction avec certains types de paramètres. Par exemple:
template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
return f(a);
}
Je ne vois pas vraiment la différence avec le code suivant:
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
return f(a);
}
ou
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
return f(a);
}
Le seul problème que je vois avec ces deux solutions est que nous devons soit:
- avoir une instance du foncteur pour l'utiliser dans l'expression passée à decltype.
- connaître un constructeur défini pour le foncteur.
Ai-je raison de penser que la seule différence entre decltype
et result_of
est que le premier a besoin d'une expression alors que le second n'en a pas?
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 lambdasstd::declval
, comme le code que j'ai montré ci-dessus. Bien sûr, c'est moche :)result_of
et son type d'assistanceresult_of_t
sont obsolètes à partir de C ++ 17 en faveur deinvoke_result
etinvoke_result_t
, allégeant certaines restrictions du premier. Ceux-ci sont répertoriés au bas de en.cppreference.com/w/cpp/types/result_of .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...)>
etdecltype(std::declval<F>()(std::declval<Args>()...)
), alors il y a une différence.std::result_of<F(Args...)
est défini comme:La différence entre
result_of<F(Args..)>::type
etdecltype(std::declval<F>()(std::declval<Args>()...)
est tout à propos de celaINVOKE
. L'utilisation dedeclval
/decltype
directement, en plus d'être un peu plus longue à taper, n'est valide que si elleF
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 celastd::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 deF
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.:L'utilisation correcte aurait été
result_of_t<F&()>
, mais c'est un détail dont vous n'avez pas à vous souvenirdecltype
.la source
T
et une fonction sans référencetemplate<class F> result_of_t<F&&(T&&)> call(F&& f, T&& arg) { return std::forward<F>(f)(std::move(arg)); }
, est-ce que l'utilisation de estresult_of_t
correcte?f
est aconst T
, devons-nous l'utiliserresult_of_t<F&&(const T&)>
?