Tengo algunos problemas para comprender la necesidad de std::result_ofC ++ 0x. Si he entendido bien, result_ofse usa para obtener el tipo resultante de invocar un objeto de función con ciertos tipos de parámetros. Por ejemplo:
template <typename F, typename Arg>
typename std::result_of<F(Arg)>::type
invoke(F f, Arg a)
{
return f(a);
}
Realmente no veo la diferencia con el siguiente código:
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(f(a)) //uses the f parameter
{
return f(a);
}
o
template <typename F, typename Arg>
auto invoke(F f, Arg a) -> decltype(F()(a)); //"constructs" an F
{
return f(a);
}
El único problema que puedo ver con estas dos soluciones es que necesitamos:
- tener una instancia del functor para usarlo en la expresión pasada a decltype.
- conocer un constructor definido para el functor.
¿Estoy en lo cierto al pensar que la única diferencia entre decltypey result_ofes que el primero necesita una expresión mientras que el segundo no?

decltypees más feo pero también más poderoso.result_ofsolo se puede usar para tipos que son invocables y requiere tipos como argumentos. Por ejemplo, no puede usarresult_ofaquí:template <typename T, typename U> auto sum( T t, U u ) -> decltype( t + u );si los argumentos pueden ser tipos aritméticos (no hay una funciónFtal que pueda definirF(T,U)para representart+u. Para tipos definidos por el usuario, podría hacerlo. De la misma manera (realmente no he jugado con eso) imagino que las llamadas a métodos de miembros pueden ser difíciles de realizarresult_ofsin usar carpetas o lambdasstd::declval, como el código que he mostrado arriba. Por supuesto, esto es feo :)result_ofy su tipo de ayudaresult_of_testán en desuso a partir de C ++ 17 a favor deinvoke_resultyinvoke_result_t, aliviando algunas restricciones del primero. Estos se enumeran al final de en.cppreference.com/w/cpp/types/result_of .Si necesita el tipo de algo que no es algo así como una llamada de función,
std::result_ofsimplemente no se aplica.decltype()puede darte el tipo de cualquier expresión.Si nos limitamos a las diferentes formas de determinar el tipo de retorno de una llamada de función (entre
std::result_of_t<F(Args...)>ydecltype(std::declval<F>()(std::declval<Args>()...)), entonces hay una diferencia.std::result_of<F(Args...)Se define como:La diferencia entre
result_of<F(Args..)>::typeydecltype(std::declval<F>()(std::declval<Args>()...)se trata de esoINVOKE. Usardeclval/decltypedirectamente, además de ser un poco más largo de escribir, solo es válido siFse puede llamar directamente (un tipo de objeto de función o una función o un puntero de función).result_ofademás, admite punteros a funciones de miembros y punteros a datos de miembros.Inicialmente, usar
declval/decltypegarantizaba una expresión compatible con SFINAE, mientras questd::result_ofpodría generar un error grave en lugar de un error de deducción. Eso se ha corregido en C ++ 14:std::result_ofahora se requiere que sea compatible con SFINAE (gracias a este documento ).Entonces, en un compilador conforme a C ++ 14,
std::result_of_t<F(Args...)>es estrictamente superior. Es más claro, más corto y correctamente † admite másFs ‡ .† A menos que, es decir, lo esté utilizando en un contexto en el que no desea permitir punteros a los miembros, por
std::result_of_tlo que tendría éxito en un caso en el que desee que falle.‡ Con excepciones. Si bien admite punteros a miembros,
result_ofno funcionará si intenta crear una instancia de un identificador de tipo no válido . Estos incluirían una función que devuelve una función o que toma tipos abstractos por valor. Ex.:El uso correcto habría sido
result_of_t<F&()>, pero ese es un detalle que no tiene que recordardecltype.fuente
Ty una funcióntemplate<class F> result_of_t<F&&(T&&)> call(F&& f, T&& arg) { return std::forward<F>(f)(std::move(arg)); }, ¿esresult_of_tcorrecto el uso de ?fes aconst T, ¿deberíamos usarresult_of_t<F&&(const T&)>?