2010-01-05 6 views
8

Estoy buscando una forma en C++ para extraer el tipo de devolución de una función (sin llamarla). Supongo que esto requerirá algo de magia de plantilla.Extraiga el tipo de devolución de una función sin llamarla (¿con plantillas?)

float Foo(); 
int Bar(); 

magic_template<Foo>::type var1; // Here 'var1' should be of type 'float' 
magic_template<Bar>::type var2; // and 'var2' should be of type 'int' 

actualmente estoy investigando cómo podría implementarse magic_template, pero no han encontrado una solución hasta el momento.

¿Alguna idea?

Respuesta

7

Eche un vistazo a la biblioteca boost type traits, en particular, la plantilla function_traits proporciona dicha funcionalidad lista para usar. Si no puede usar el impulso, simplemente descargue el código y lea las fuentes para tener una idea de cómo se hace.

Tenga en cuenta que la funcionalidad se basa en tipos, no en funciones concretas, por lo que es posible que deba agregar algún código adicional allí.


Después de hacer algunas pruebas pequeñas, esto podría no ser lo que realmente necesita, y si es el 'algún código extra' será no trivial. El problema es que la plantilla function_traits funciona en firmas de función y no en punteros de función reales, por lo que el problema ha cambiado de 'obtener el tipo de retorno de un puntero de función' a 'obtener la firma de un puntero de función' que es probablemente la parte más difícil .

+1

Los tipos de devolución de función son covariantes, un iceberg que hundirá ese Titanic. –

+0

Hmm sí, esto se ve bien. Para dar un ejemplo a todos, funciona así: boost :: function_traits :: type> :: result_type var1; var1 = 3.14f; Mi único problema ahora es como dijiste, necesito el tipo de función completa para pasar a estas utilidades de refuerzo. – pauldoo

+0

@nobugz: Realmente no entiendo tu comentario, ¿puedes explicarlo más? –

-1

intentar algo como esto:

template<class T> struct magic_template 
{}; 

template<class T> struct magic_template<T()> 
{ 
    typedef T type; 
}; 
5

Es difícil porque los nombres de función son tipos expresión no - se necesita algo así como gcc de typeof. El TypeOf de Boost es una solución portátil que se acerca mucho.

Sin embargo, si el código puede ser organizado de tal manera que el trabajo se realiza dentro de una plantilla de función a la que Foo o Bar se puede pasar, hay una respuesta recta de avance:

template <class R> 
void test(R (*)()) 
{ 
    R var1; 
} 

int main() 
{ 
    test(&Foo); 
} 
4

Foo y el bar son funciones , no tipos de funciones, por lo que necesita hacer un poco de trabajo extra.

Aquí hay una solución que usa una combinación de boost :: function_traits y BOOST_TYPEOF.

#include <boost/typeof/typeof.hpp> 
#include <boost/type_traits.hpp> 

float Foo(); 
int Bar(); 

int main() 
{ 
    boost::function_traits<BOOST_TYPEOF(Foo)>::result_type f = 5.0f; 
    boost::function_traits<BOOST_TYPEOF(Bar)>::result_type i = 1; 
    return i; 
} 

Editar:

  • Esto funcionará para funciones de cualquier aridad hasta 10, que debería ser suficiente para los usos más sensibles.
  • Este uso de BOOST_TYPEOF funciona en plataformas que no proporcionan un typeof nativo, por lo que es razonablemente portable.
0

Como sugiere dribeas, aquí está la solución el tiempo llegué a:

float Foo(); 
int Bar(); 

template<typename T> Monkey(T) { 
    boost::function_traits< boost::remove_pointer<T>::type >::result_type var1 = ...; 
    // Now do something 
} 

Monkey(Foo); 
Monkey(Bar); 

Esto no es exactamente la forma apunté con mi pregunta original, pero es lo suficientemente cerca para mí.

+0

Necesita 'nombre de tipo' adicional en allí: typename boost :: function_traits :: type> :: result_type –

+0

Puedes perder el remove_pointer simplemente haciendo que la firma quede vacía Monkey (T *) [oh sí, te perdiste el tipo de devolución de Monkey también] –

1

Aquí viene la magia plantilla (sin Boost es implicado) :

template <typename ReturnType> class clFunc0 
{ 
    typedef ReturnType (*FuncPtr)(); 
public: 
    typedef ReturnType Type; 
}; 

template <typename ReturnType> inline clFunc0<ReturnType> ResultType(ReturnType (*FuncPtr)()) 
{ 
    return clFunc0<ReturnType>(); 
} 

#define FUNC_TYPE(func_name) decltype(ResultType(&func_name))::Type 

int test() 
{ 
    return 1; 
} 

int main() 
{ 
    FUNC_TYPE(test) Value = 1; 

    return Value; 
} 

y compilarlo a través

gcc Test.cpp -std=gnu++0x 
+1

No hay necesidad de nada de esto en C++ 11, que tiene 'std :: result_of'. – Potatoswatter

Cuestiones relacionadas