verificar revista oficina lecturas horas gubernamental funcion etica ethos certificacion acceso c++ templates return-value overloading c++11

c++ - revista - Extrayendo el tipo de devolución de una función sobrecargada



revista ethos (3)

Creo que esto se puede hacer con decltype y declval :

Por ejemplo: decltype(f(std::declval<T>())) .

Quiero extraer el tipo de devolución de una función. El problema es que hay otras funciones con el mismo nombre pero diferente firma, y ​​no puedo obtener C ++ para seleccionar la apropiada. Sé de std :: result_of, pero a partir de algunos intentos he llegado a la conclusión de que también sufre el mismo problema. También he oído hablar de una solución que involucra a decltype, pero no conozco ningún detalle.

En este momento estoy usando la metaprogramación de plantillas para extraer el tipo de retorno de un tipo de puntero a función, que funciona bien para un número limitado de parámetros (¿alguna solución no limitada?), Dado que la extracción del tipo de puntero funciona para funciones no ambiguas.

#include <iostream> using namespace std; // ---- #define resultof(x) typename ResultOf<typeof(x)>::Type // might need a & before x template <class T> class ResultOf { public: typedef void Type; // might need to be T instead of void; see below }; template <class R> class ResultOf<R (*) ()> { public: typedef R Type; }; template <class R, class P> class ResultOf<R (*) (P)> { public: typedef R Type; }; // ---- class NoDefaultConstructor { public: NoDefaultConstructor (int) {} }; int f (); int f () { cout << "f" << endl; return 1; } double f (int x); double f (int x) { cout << "f(int)" << endl; return x + 2.0; } bool f (NoDefaultConstructor); bool f (NoDefaultConstructor) { cout << "f(const NoDefaultConstructor)" << endl; return false; } int g (); int g () { cout << "g" << endl; return 4; } int main (int argc, char* argv[]) { if(argc||argv){} // this works since there is no ambiguity. does not work without & // resultof(&g) x0 = 1; // cout << x0 << endl; // does not work since type of f is unknown due to ambiguity. same thing without & // resultof(&f) x1 = 1; // cout << x1 << endl; // does not work since typeof(f()) is int, not a member function pointer; we COULD use T instead of void in the unspecialized class template to make it work. same thing with & // resultof(f()) x2 = 1; // cout << x2 << endl; // does not work per above, and compiler thinks differently from a human about f(int); no idea how to make it correct // resultof(f(int)) x3 = 1; // cout << x3 << endl; // does not work per case 2 // resultof(f(int())) x4 = 1; // cout << x4 << endl; // does not work per case 2, and due to the lack of a default constructor // resultof(f(NoDefaultConstructor())) x5 = 1; // cout << x5 << endl; // this works but it does not solve the problem, we need to extract return type from a particular function, not a function type // resultof(int(*)(int)) x6 = 1; // cout << x6 << endl; }

¿Alguna idea de qué característica de sintaxis me falta y cómo solucionarlo, preferiblemente con una solución que funciona de una manera simple, por ejemplo, resultof(f(int)) ?


De acuerdo, después de algunos intentos me las arreglé para std::declval método std::declval sugerido por Mankarse. Usé una plantilla de clase variadic para fijar los parámetros y usé la deducción de funciones de la plantilla para obtener el valor de retorno de un puntero de función. Su sintaxis actual es typeof(ResultOf<parameters>::get(function)) , desafortunadamente aún está lejos del resultado deseado de la resultof<parameters>(function) . Editaré esta respuesta si encuentro una forma de simplificarla aún más.

#include <iostream> #include <typeinfo> using namespace std; template <class... Args> class ResultOf { public: template <class R> static R get (R (*) (Args...)); template <class R, class C> static R get (R (C::*) (Args...)); }; class NoDefaultConstructor { public: NoDefaultConstructor (int) {} }; int f (); double f (int x); bool f (NoDefaultConstructor); int f (int x, int y); int main (int argc, char* argv[]) { if(argc||argv){} cout << typeid(typeof(ResultOf<>::get(f))).name() << endl; cout << typeid(typeof(ResultOf<int>::get(f))).name() << endl; cout << typeid(typeof(ResultOf<NoDefaultConstructor>::get(f))).name() << endl; cout << typeid(typeof(ResultOf<int, int>::get(f))).name() << endl; typeof(ResultOf<int>::get(f)) d = 1.1; cout << d << endl; }

Editar:

Gestionado para resolverlo con macros variadas, la sintaxis ahora es resultof(f, param1, param2, etc) . Sin ellos, no podría pasar las comas entre los tipos de parámetros a la plantilla. resultof(f, (param1, param2, etc)) con la sintaxis resultof(f, (param1, param2, etc)) en vano.

#include <iostream> using namespace std; template <class... Args> class Param { public: template <class R> static R Func (R (*) (Args...)); template <class R, class C> static R Func (R (C::*) (Args...)); }; #define resultof(f, ...) typeof(Param<__VA_ARGS__>::Func(f)) int f (); double f (int x); int f (int x, int y); int main (int argc, char* argv[]) { resultof(f, int) d = 1.1; cout << d << endl; }


Es muy difícil inspeccionar un nombre de función sobrecargado sin argumentos. Puede inspeccionar los tipos de devolución de sobrecargas que difieren en aridad, siempre que ninguna arity tenga más de una sobrecarga. Incluso entonces, convertir un error difícil (si / cuando una aridad dada tiene más de una sobrecarga) en SFINAE es un problema ya que requiere escribir un rasgo solo para esa función particular (!) Ya que los nombres de funciones sobrecargados no se pueden pasar como cualquier tipo de argumento También podría requerir código de usuario para usar una especialización explícita ...

template<typename R> R inspect_nullary(R (*)()); template<typename R, typename A0> R inspect_unary(R (*)(A0)); int f(); void f(int); int g(); double g(); typedef decltype(inspect_nullary(f)) nullary_return_type; typedef decltype(inspect_unary(f)) unary_return_type; static_assert( std::is_same<nullary_return_type, int>::value, "" ); static_assert( std::is_same<unary_return_type, void>::value, "" ); // hard error: ambiguously overloaded name // typedef decltype(inspect_nullary(g)) oops;

Dado que está usando C ++ 0x, siento la necesidad de señalar que (IMO) nunca es necesario inspeccionar un tipo de devolución más allá de typename std::result_of<Functor(Args...)>::type y eso no se aplica a los nombres de funciones; pero tal vez su interés en esto es puramente académico.