2009-07-08 14 views
6

Estoy tratando de punteros de función miembro importancia a las plantillas de la siguiente manera: (Esta es una versión simplificada de mi código real)sobrecargado puntero de función miembro a la plantilla

template<class Arg1> 
void connect(void (T::*f)(Arg1)) 
{ 
    //Do some stuff 
} 

template<class Arg1> 
void connect(void (T::*f)()) 
{ 
    //Do some stuff 
} 

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 

entonces quiero hacer como los siguientes para cada métodos sobrecargados en GAPP:

connect(&GApp::foo); 

para llamar a este foo() está bien, pero ¿cómo puedo llamar a esto para foo(double d)? ¿Por qué no funciona lo siguiente?

connect((&GApp::foo)(double)); 

Me dará

error de sintaxis: 'doble' debe ir precedida de ')'

No entiendo la sintaxis que debe ser utilizado aquí. Esto puede ser una pregunta estúpida, pero ¿alguien me puede ayudar en esto?

+0

Es una mejor idea usar Functors en lugar de punteros a funciones en mi humilde opinión. – Drakosha

+0

Todo el código es parte de la implementación de un mecanismo de Señal y Ranura. Entonces, el litener (que tiene la ranura) no quiere saber sobre el sistema. Entonces, no puedo decirle al oyente que haga esto, haga esto ... – Morpheus

Respuesta

6

Su código tal como está escrito no compila. He hecho algunas "suposiciones" sobre lo que quería hacer y he cambiado el código.

En resumen, se puede llamar a la función correcta al especificar explícitamente el tipo de parámetro de función:

connect<double> (&GApp::foo); 

Si los métodos de conexión son miembros de una plantilla de clase, entonces sólo es necesario especificar el tipo de clase una vez :

template <typename T> class A 
{ 
public: 
    template<class Arg1> 
    void connect(void (T::*f)(Arg1)) 
    { 
    //Do some stuff 
    } 

    void connect(void (T::*f)()) 
    { 
    //Do some stuff 
    } 
}; 

class GApp 
{ 
public: 
    void foo() {} 
    void foo(double d) {} 
}; 


int main() 
{ 
    A<GApp> a; 
    a.connect (&GApp::foo);   // foo() 
    a.connect<double> (&GApp::foo); // foo (double) 
} 

ACTUALIZACIÓN:

en respuesta al nuevo código de ejemplo, en toda la la formación se está transfiriendo. El caso "raro" es el caso "signal_void", ya que aquí es donde la señal tiene un argumento de plantilla, pero la función miembro no. Por lo tanto, hacemos un caso especial de ese ejemplo y luego terminamos. La siguiente ahora compila:

template <class Arg = void> 
class signal {}; 
signal<double> signal_double; 
signal<> signal_void; 

// Arg1 is deduced from signal<Arg1> and then we use it in the declaration 
// of the pointer to member function 
template<class T, class Arg1> 
void connect (signal<Arg1>& sig, T& obj, void (T::*f)(Arg1)) {} 

// Add special case for 'void' without any arguments 
template<class T> 
void connect (signal<> & sig, T& obj, void (T::*f)()) {} 


void bar() 
{ 
    GApp myGApp; 

    //Connecting foo() 
    connect(signal_void, myGApp, &GApp::foo); // Matches second overload 

    //Connecting foo(double) 
    connect(signal_double, myGApp, &GApp::foo); // Matches first overload 
} 
+0

¡Oye! Gracias por el esfuerzo. Lo siento, olvidé decir que mi código no está completo. Fue porque eliminé la clase de plantilla de señal para simplificar el código. Por cierto, sí, tu método está funcionando bien. Voy a publicar mi código original, ¿puedes mirarlo entonces? Gracias – Morpheus

+1

Wohooooo .... yeah. Usted me muestra el camino. Ahora todos están funcionando correctamente. Muchas gracias. – Morpheus

1

Usted puede tratar de forma explícita el puntero fundición, para hacerle saber cuál elegir, así:

connect((void (GApp::*)(double))&GApp::foo); 

exención de responsabilidad: no han probado

+0

Gracias por los ans. Sí, está funcionando ... – Morpheus

+0

No puede ser seguro: un molde es simplemente una función en el puntero GApp :: foo. No cambiará el contenido del puntero. – xtofl

+0

Tengo la teoría de que es seguro, ver mi respuesta para más detalles. Sin embargo, todavía no lo he confirmado en el estándar, porque tengo una fuerte sospecha de que el lenguaje del estándar coincidirá con el de Stroustrup en C++ PL de todos modos, y es una pregunta un tanto complicada. –

0

esto está funcionando,

typedef void (GApp::*MemberFunctionType)(double); 
    MemberFunctionType pointer = &GApp::foo; 


    connect(MemberFunctionType); 

¿Por qué es eso?

EDIT

hmm .. yeah. Es lo mismo que la solución de newacct. ¿Alguien puede dar una solución por favor?

+0

Mi respuesta explica por qué esto funciona, por referencia a Stroustrup y una suposición de que lo que dice sobre los punteros de función se aplica también a los punteros de función de miembro. –

0

El uso de la biblioteca impulso :: función ...

#include <boost/function.hpp> 

template<class Arg1> 
void connect(boost::function1<void, Arg1*> fn) 
{ 
    //Do some stuff 
} 

template<class Arg1> 
void connect(boost::function2<void, Arg1*, double> fn) 
{ 
    //Do some stuff 
} 

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 


int main() 
{ 
    boost::function1<void,GApp*> f1 = (void (GApp::*)(void)) &GApp::foo; 
    boost::function2<void,GApp*,double> f2 = (void (GApp::*)(double)) &GApp:foo; 
    connect(f1); 
    connect(f2); 
    return 0; 
} 
+0

¡Oye! Gracias por los ans. No es tu (void (GApp :: *) (double)) & GApp: foo; igual que la solución newacct, (void (GApp :: *) (double)) & GApp :: foo. Pero xtofl dijo que no es seguro :( – Morpheus

+0

xtofl ha actualizado el comentario para decir que parece ser seguro. Es preferible usar objetos de función en lugar de indicadores de función, eso es todo. – Anshul

0

Mi código original es así,

conectores ....

template<class T, class Arg1> 
void connect(signal<Arg1>& sig,T& obj, void (T::*f)()) 
{ 
// sig.insert(new GFunction<T, Arg1>(&obj,f)); 
} 

template<class T, class Arg1 
void connect(signal<Arg1>& sig,T& obj, void (T::*f)(Arg1)) 
{ 
// sig.insert(new GFunction<T, Arg1>(&obj,f)); 
} 

Signals ...

signal<double> signal_double; 
signal<> signal_void; 

aplicación ...

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 

Finaly, conectando ...

//Connecting foo() 
     connect(signal_void, myGApp, &GApp::foo()); //Ok 

//Connecting foo(double) 
     connect(signal_double, myGApp, &GApp::foo()); // but ERROR! 

Hay classs plantilla para señales (que no se mencionan aquí). Espero que ahora esté más clara la situación. (¿o es lo mismo que use el símbolo?). Esa segunda conexión funcionará si no hay foo() (solo foo (doble)). Eso es lo que mi código me lastima. :(

5

El C++ Programming Language, 3E, Sección 7.7, P159:.

Usted puede tomar la dirección de una función sobrecargada mediante la asignación o inicializar un puntero a función en ese caso, el tipo de el objetivo se utiliza para seleccionar entre el conjunto de funciones sobrecargadas Por ejemplo:.

void f(int); 
int f(char); 

void (*pf1)(int) = &f; // void f(int); 
int (*pf2)(char) = &f; // int f(char); 
void (*pf3)(char) = &f; // error: no void f(char) 

Por lo que yo sé (no comprobado), lo mismo se aplica a las funciones miembro Así que la solución es probablemente a. dividir en dos líneas:

connect((&GApp::foo)(double)); 

se convierte en:

void (GApp::*tmp)(double) = &GApp::foo; 
connect(tmp); 

Nunca llaman variables de tmp ;-)

Me imagino que el elenco de newacct es seguro también, por la misma razón. Casting a void (GApp::*)(double) se define como lo mismo que la inicialización de un temporal de tipo void (GApp::*)(double). Dado que la expresión utilizada para inicializarlo es &GApp::foo, esperaría que se aplicara la misma magia al molde como se aplica a cualquier otra inicialización con una función sobrecargada. Stroustrup no dice "inicializando una variable de puntero a función", dice "inicializando un puntero a función". Entonces eso debería incluir los temporales.

Así que si usted prefiere una sola línea:

connect((void (GApp::*)(double))(&GApp::foo)); 

Sin embargo, estoy suponiendo que la norma tiene la misma idea de la consistencia como yo, y yo no lo he comprobado.

+0

¡GRACIAS! ¡Por eso el elenco funcionará! – xtofl

+0

¡Y dicen que C++ es difícil de entender! ;-) –

Cuestiones relacionadas