c++ c++11 std result-of

c++ - std:: result_of simple function



c++11 result-of (1)

std::result_of<T> requiere que T sea ​​un tipo --pero no cualquier tipo. T debe ser un tipo de función para que se utilice esta especialización parcial de result_of :

template <class Fn, class... ArgTypes> struct result_of<Fn(ArgTypes...)>;

tal que

decltype(INVOKE(declval<Fn>(), declval<ArgTypes>()...))

está bien formado (C ++ 11 20.9.7.6). (INVOKE se define en 20.8.2.)

La razón por la cual std::result_of<f(int)> no funciona es porque f no es un tipo --es una instancia de un tipo de función. Para declarar que x es el tipo de retorno de f aplicado a un int , simplemente escriba esto:

decltype(f(int{})) x;

o si prefieres codificar un int :

decltype(f(32)) x;

Si se desea el tipo de f entonces use:

using FuncPtr = decltype(f);

En el código provisto F (es decir, no en minúsculas f ), sin embargo, es un tipo, por lo que F(int) define un tipo que representa la función que devuelve F aceptando un int como argumento. ¡Claramente esto no es lo que F es! El tipo de F es una estructura cuyas instancias pueden usar el operador de llamada de función. F tampoco tiene constructores explícitos o implícitos que tomen un int , etc. también. ¿Cómo puede funcionar esto? Respuesta corta: Plantilla "magia".

Esencialmente, la definición de std::result_of toma el tipo, F(int) y separa el tipo de retorno de los tipos de argumentos para que pueda determinar qué caso de INVOKE () permitiría que funcionara. Los casos de INVOKE son:

  1. F es un puntero a una función miembro para alguna clase T
  2. Si solo hay un argumento, F es un puntero a un miembro de datos de la clase T, o
  3. Una instancia de F se puede utilizar como una función, es decir,

declval<F>()(declval<int>())

que puede ser una llamada de función normal o algún tipo de functor (por ejemplo, como su ejemplo).

Una vez que se haya determinado esto, result_of puede determinar el tipo de retorno de la expresión válida. Esto es lo que se devuelve a través del miembro de type result_of .

Lo bonito de esto es que el usuario de result_of no necesita saber nada sobre cómo funciona esto realmente. Lo único que hay que entender es que result_of necesita una función TYPE. Si uno usa nombres que no son tipos dentro del código (por ejemplo, f ), entonces se deberá usar decltype para obtener el tipo de expresión con los decltype .

Finalmente, parte de la razón por la que f no se puede considerar como un tipo es porque los parámetros de la plantilla también permiten valores constantes y f es un valor de puntero de función constante. Esto se demuestra fácilmente (usando la definición de f de la pregunta):

template <double Op(int)> double invoke_op(int i) { return Op(i); }

y después:

std::cout << invoke_op<f>(10) << std::endl;

Entonces, para obtener el tipo de valor de retorno de una expresión invocando f con algún int se escribiría:

decltype(f(int{}))

(Nota: f nunca se llama: el compilador simplemente usa la expresión dentro de decltype para determinar su resultado, es decir, su valor de retorno en esta instancia).

#include <iostream> #include <type_traits> double f(int i) { return i+0.1; } struct F { public: double operator ()(int i) { return i+0.1; } }; int main(int, char**) { std::result_of<F(int)>::type x; // ok // std::result_of<f(int)>::type x; // error: template argument 1 is invalid x = 0.1; std::cerr << x << std::endl; }

Por favor explique por qué std::result_of<f(int)>::type x; no es válido...

cppreference dice "( std::result_of ) Deduce el tipo de retorno de una expresión de llamada de función en el tipo de compilación".

¿Cuál es el problema?