2011-05-16 15 views
10

Estoy escribiendo un envoltorio función generalizada, que puede envolver cualquier función en una llamada de estilo lua, que tiene la formafunciona como un argumento de plantilla, además de parámetro de plantilla variadic

int lua_function (lua_State * L)

Y me gustaría que la función de envoltura se genere sobre la marcha, así que estoy pensando en pasar la función como un argumento de plantilla. Esto es trivial si se conoce el número (por ejemplo, 2) de argumentos:

template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)> 
struct wrapper 

Sin embargo, no sé el número, por lo que pido para el argumento de plantilla variadic ayuda

// This won't work 
template <typename R, typename... Args, R F(Args...)> 
struct wrapper 

El arriba no compilará, ya que el argumento variadico tiene que ser el último. Así que utilizo dos plantilla de nivel, la plantilla externa capta tipos, la plantilla interior capta la función:

template <typename R, typename... Args> 
struct func_type<R(Args...)> 
{ 
    // Inner function wrapper take the function pointer as a template argument 
    template <R F(Args...)> 
    struct func 
    { 
    static int call(lua_State *L) 
    { 
     // extract arguments from L 
     F(/*arguments*/); 
     return 1; 
    } 
    }; 
}; 

que funciona, excepto que para envolver una función como

double sin(double d) {} 

el usuario tiene que escribir

func_type<decltype(sin)>::func<sin>::apply 

que es tedioso. La pregunta es: ¿hay alguna forma mejor y más amigable para el usuario de hacerlo? (No puedo utilizar una plantilla de función para envolver todo el asunto, coz de un parámetro de función no puede ser utilizada como un argumento de plantilla.)

+0

Creo que el puntero a la función puede ser un argumento de plantilla. Funciona al menos para MSVC. Se está resolviendo un problema similar al suyo aquí: http://stackoverflow.com/questions/4387971/c-pasar-metodo-de-metodo-por-template-argumento. –

Respuesta

9

Cosas como std::function y std::result_of utilizan la siguiente técnica para hacer lo que quiera con respecto a las plantillas variadic:

template<typename Signature> 
struct wrapper; // no base template 

template<typename Ret, typename... Args> 
struct wrapper<Ret(Args...)> { 
    // instantiated for any function type 
}; 

Se podría ampliar el anterior para agregar un parámetro de plantilla no Tipo de Ret(&P)(Args...) (punteros a función de trabajo del mismo modo bien) pero aún necesitaría un decltype en el nivel de usuario, es decir, wrapper<decltype(sin), sin>::apply. Podría decirse que sería un uso legítimo del preprocesador si decide utilizar una macro para eliminar la repetición.

template<typename Sig, Sig& S> 
struct wrapper; 

template<typename Ret, typename... Args, Ret(&P)(Args...)> 
struct wrapper<Ret(Args...), P> { 
    int 
    static apply(lua_State*) 
    { 
     // pop arguments 
     // Ret result = P(args...); 
     // push result & return 
     return 1; 
    } 
}; 

// &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function. 

Las compilaciones anteriores con gcc-4.5 en ideone. Buena suerte con la implementación de la aplicación que (de forma variada) muestra los argumentos (déjame un comentario si abres una pregunta al respecto). ¿Has considerado usar Luabind?

+0

Gracias Luc, creo que es mucho lo que podemos obtener sin macro. Por cierto, para mi propósito (envolviendo c sencilla ++ funciones), escribir un "Aplicar" es fácil, sólo escribo un montón de especialización de plantilla llamada extract_arg <> y hacer esto statci aplican (lua_State * L) { P (extract_arg (L) ...); } –

0

Como dice @Juraj en su comentario, la función de puntero puede ser una argumento de plantilla, ver el siguiente ejemplo sencillo:

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

void f(int b, double c, std::string const& g) 
{ 
    std::cout << "f(): " << g << std::endl; 
} 

template <typename F, F* addr> 
struct wrapper 
{ 
    void operator()() 
    { 
    std::string bar("bar"); 
    (*addr)(1, 10., bar); 
    } 
}; 

int main(void) 
{ 
    wrapper<BOOST_TYPEOF(f), &f> w; 
    w(); 
    return 0; 
} 

versión de trabajo: http://www.ideone.com/LP0TO

estoy usando BOOST_TYPEOF ya que normalmente siempre proporcionan ejemplos en la norma actual, pero hace algo similar a decltype. ¿Es esto lo que estabas buscando?

Cuestiones relacionadas