Si necesita el tipo de algo que no es algo así como una llamada a la función, simplemente no std::result_of
aplicar. decltype()
puede darle el tipo de cualquier expresión.
Si nos limitamos solo a las diferentes formas de determinar el tipo de devolución de una llamada a función (entre std::result_of_t<F(Args...)>
y decltype(std::declval<F>()(std::declval<Args>()...)
), entonces hay una diferencia.
std::result_of<F(Args...)
se define como:
Si la expresión INVOKE (declval<Fn>(), declval<ArgTypes>()...)
es bien formado cuando son tratados como un operando sin evaluar (cláusula 5), el tipo typedef miembro nombrará el tipo decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
lo contrario, no habrá ningún tipo de miembro .
La diferencia entre result_of<F(Args..)>::type
y decltype(std::declval<F>()(std::declval<Args>()...)
es todo acerca de eso INVOKE
. El uso de declval
/decltype
directamente, además de ser bastante más largo de escribir, solo es válido si F
es directamente invocable (un tipo de objeto de función o una función o un puntero de función).result_of
, además, admite punteros a funciones de miembros y punteros a datos de miembros.
Inicialmente, utilizando declval
/decltype
garantiza una expresión SFINAE de usar, mientras que std::result_of
que podría dar un error de hardware en lugar de un fallo de la deducción. Eso se ha corregido en C++ 14: std::result_of
ahora se requiere que sea compatible con SFINAE (gracias a this paper).
Por lo tanto, en un compilador C++ 14 conforme, std::result_of_t<F(Args...)>
es estrictamente superior. Es más claro, más corto y correctamente & dagger; admite más F
s & Dagger;.
& dagger; A menos que, es decir, lo esté usando en un contexto en el que no desea permitir punteros a los miembros, por lo que
std::result_of_t
tendrá éxito en caso de que desee que falle.
& Dagger; Con excepciones. Si bien admite punteros a miembros, result_of
no funcionará si intenta crear una instancia de tipo-id no válida. Estos incluirían una función que devuelve una función o toma tipos abstractos por valor. Ej .:
template <class F, class R = result_of_t<F()>>
R call(F& f) { return f(); }
int answer() { return 42; }
call(answer); // nope
El uso correcto hubiera sido result_of_t<F&()>
, pero eso es un detalle que no tiene que recordar con decltype
.
Ok, por lo que es principalmente una clase de conveniencia para evitar la expresión fea en decltype, ¿verdad? –
@Luc: Sí. :) (¡Tarde!) – GManNickG
@GMan: Mejor tarde que nunca;)! –