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...)>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>()...)está bien formada cuando se trata como un operando no evaluado (cláusula 5), el tipo de miembro typedef nombrará el tipo; de lo decltype(INVOKE (declval<Fn>(), declval<ArgTypes>()...));
contrario, no habrá ningún tipo de miembro.
La diferencia entre result_of<F(Args..)>::typey decltype(std::declval<F>()(std::declval<Args>()...)se trata de eso INVOKE. Usar declval/ decltypedirectamente, además de ser un poco más largo de escribir, solo es válido si Fse 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 que std::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ás Fs ‡ .
† 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.:
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 habría sido result_of_t<F&()>, pero ese es un detalle que no tiene que recordar decltype.
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 lambdas