2011-11-22 12 views
6

Considere Tengo una función declaraciones como éstas:Recuperar argumentos de la función como una tupla en C++

void foo(int x, float y); 

class X { 
    void anotherFoo(double a, int c); 
}; 

¿Cómo puedo obtener una tupla que corresponde a los argumentos de la función? En el caso anterior sería:

boost::tuple<int, float> 
boost::tuple<X*, double, int> 

o incluso mejor con el resultado de 0 ª tipo de elemento como:

boost::tuple<void, int, float> 
boost::tuple<void, X*, double, int> 

sé que boost::function_types::parameter_types puede hacer exactamente esto. Sin embargo, estoy interesado en el principio de cómo se implementa.

+0

Yo usaría una 'struct'. ¿Cuál es el objetivo/ventaja de usar tuplas? – kol

+0

@kol código menos repetitivo, menos ruido – daramarak

+0

¿Quiere decir que desea generar automáticamente el tipo de tupla en tiempo de compilación o tiempo de ejecución, o desea extraer los parámetros de la regla/pila, o ambos, o alguna otra cosa? – Rup

Respuesta

9

Puede obtener la tupla tipo correspondiente a su argumento tipos, así:

template <typename R, typename... T> 
std::tuple<T...> function_args(R (*)(T...)) 
{ 
    return std::tuple<T...>(); 
} 

// get the tuple type 
typedef decltype(function_args(foo)) FooArgType; 
// create a default-initialised tuple 
auto args = function_args(foo); 

es eso lo que quieres? Tenga en cuenta que puede necesitar agregar una o más sobrecargas de function_args, ej. tomando un param de tipo de clase para los métodos de clase.

+0

¿Sigue funcionando el 'decltype' si la función no se puede instanciar porque uno o más de sus tipos de parámetros no pueden ser inicializado por defecto? Y si no, ¿hay alguna solución con un puntero que lo haría? –

+0

Todavía puede utilizar el 'decltype (function_args (foo))' en un typedef o lo que sea, pero nunca se puede realmente _call_ 'function_args 'en ese caso. – Useless

+0

Esto funciona, gracias. ¿Hay alguna manera de evitar el decltype (ya que solo es C++ 11)? Boost funciona incluso en compiladores que no sean C++ 11, así que esto podría lograrse de alguna manera. –

2

Finalmente encontré la forma de hacerlo en C++ 03 utilizando la especialización parcial. Una gran cantidad de sobrecargas para diferente número de argumentos y funciones const/volátil son necesarias pero la idea es siguiente: el uso

/* An empty template struct, this gets chosen if the given template parameter is not a member function */ 
template <typename _Func> 
struct MemberFunctionInfo { }; 

/* Specialization for parameterless functions */ 
template <typename _Result, typename _Class> 
struct MemberFunctionInfo<_Result (_Class::*)()> { 
    typedef _Class class_type; 
    typedef _Result result_type; 
    typedef boost::tuple<> parameter_types; 
    enum { arity = 0 }; 
}; 

/* Specialization for parameterless const functions */ 
template <typename _Result, typename _Class> 
struct MemberFunctionInfo<_Result (_Class::*)() const> : MemberFunctionInfo<_Result (_Class::*)()> { }; 

/* Specialization for functions with one parameter */ 
template <typename _Result, typename _Class, typename P0> 
struct MemberFunctionInfo<_Result (_Class::*) (P0)> { 
    typedef _Class class_type; 
    typedef _Result result_type; 
    typedef boost::tuple<P0> parameter_types; 
    enum { arity = 1 }; 
}; 

/* Specialization for const functions with one parameter */ 
template <typename _Result, typename _Class, typename P0> 
struct MemberFunctionInfo<_Result (_Class::*) (P0) const> : MemberFunctionInfo<_Result (_Class::*) (P0)> { }; 

. 
. 
. 

Ejemplo:

template <typename MemFunc> 
int getArity(MemFunc fn) { 
    // Can also use MemberFunctionInfo<MemFunc>::parameter_types with boost::mpl 
    return MemberFunctionInfo<MemFunc>::arity; 
} 

La solución anterior tiene algunos defectos. No maneja las referencias de función, las funciones que no son miembro o las funciones de miembro volatile/const volatile, pero es fácil contabilizarlas agregando más especializaciones.

Para C++ 11, el enfoque mencionado por @Useless es mucho más limpio y debe preferirse.

Cuestiones relacionadas