2012-03-19 26 views
17

Considere este código:genérica puntero de función miembro como un parámetro de plantilla

#include <iostream> 
using namespace std; 

class hello{ 
public: 
    void f(){ 
     cout<<"f"<<endl; 
    } 
    virtual void ff(){ 
     cout<<"ff"<<endl; 
    } 
}; 

#define call_mem_fn(object, ptr) ((object).*(ptr)) 

template<R (C::*ptr_to_mem)(Args...)> void proxycall(C& obj){ 
    cout<<"hello"<<endl; 
    call_mem_fn(obj, ptr_to_mem)(); 
} 

int main(){ 
    hello obj; 
    proxycall<&hello::f>(obj); 
} 

Por supuesto, esto no se compilará en la línea 16, ya que el compilador no sabe qué R, CArgs y, lo son. Pero hay otro problema: si uno trata de definir los parámetros de plantilla justo antes ptr_to_mem, se encuentra con esta mala situación:

template<typename R, typename C, typename... Args, R (C::*ptr_to_mem)(Args...)> 
          // ^variadic template, but not as last parameter! 
void proxycall(C& obj){ 
    cout<<"hello"<<endl; 
    call_mem_fn(obj, ptr_to_mem)(); 
} 

int main(){ 
    hello obj; 
    proxycall<void, hello, &hello::f>(obj); 
} 

Sorprendentemente, g ++ no quejarse Args no ser el último parámetro en la lista de plantillas, pero de todos modos, no puede vincular proxycall a la función de plantilla correcta, y solo señala que es un posible candidato.

¿Alguna solución? Mi último recurso es pasar el puntero a la función miembro como argumento, pero si pudiera pasarlo como un parámetro de plantilla, encajaría mejor con el resto de mi código.

EDIT: Como algunos han señalado, el ejemplo parece inútil porque proxycall no va a pasar ningún argumento. Esto no es cierto en el código real en el que estoy trabajando: los argumentos se obtienen con algunos trucos de plantilla de una pila Lua. Pero esa parte del código es irrelevante para la pregunta, y bastante larga, así que no la pegaré aquí.

+0

Me parece que en realidad no necesita parámetros de plantilla variados en este caso. 'proxycall()' no va a pasar ningún argumento a la invocación del puntero a la función miembro, por lo que el uso de parámetros de plantilla variadic aparece para hacer que el problema sea más difícil de lo que debe ser. –

+1

Esto no tiene sentido. Su "call_mem_fn" #define en realidad no proporciona parámetros. Entonces, no funcionará si Args no está vacío. Entonces, ¿cómo esperas que esto realmente funcione? –

+0

El código en la pregunta es solo un ejemplo. El código real manejará funciones con un número arbitrario de argumentos, y se recuperarán de otro lugar (a saber, una pila de Lua). El código de cola de metaprogramación que capta los argumentos ya está funcionando, no lo pegaré aquí porque es muy largo. –

Respuesta

32

Usted podría intentar algo como esto:

template <typename T, typename R, typename ...Args> 
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args) 
{ 
    return (obj.*mf)(std::forward<Args>(args)...); 
} 

Uso: proxycall(obj, &hello::f);

Alternativamente, para hacer que el pTMF en un argumento de plantilla, trate de especialización:

template <typename T, T> struct proxy; 

template <typename T, typename R, typename ...Args, R (T::*mf)(Args...)> 
struct proxy<R (T::*)(Args...), mf> 
{ 
    static R call(T & obj, Args &&... args) 
    { 
     return (obj.*mf)(std::forward<Args>(args)...); 
    } 
}; 

Uso:

hello obj; 

proxy<void(hello::*)(), &hello::f>::call(obj); 

// or 

typedef proxy<void(hello::*)(), &hello::f> hello_proxy; 
hello_proxy::call(obj); 
+0

Siempre olvido que cuando tengo problemas con las plantillas de funciones, las plantillas de clase son mi bote salvavidas. –

+0

@LorenzoPistone: Por lo general, implementas tu magia con una plantilla de clase y usas especialización, y al final agregas una pequeña plantilla de * función de * deducción de tipo para que no tengas que deletrear los parámetros de la plantilla. En este caso, sin embargo, realmente no sé cómo esto ayuda, pero tal vez esto es suficiente para darte una idea. –

+1

No se olvide de tratar con las funciones miembro 'const'. (Pero si decides no molestarte con 'volátil' o' const volátil', no me quejaría.) – aschepler

Cuestiones relacionadas