2009-07-08 34 views
6

Sto cercando di puntatori a funzione membro negozio da modelli come questo: (Questa è una versione semplificata del mio codice vero e proprio)sovraccaricato puntatore a funzione membro a Template

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) {} 
}; 

poi voglio fare come quanto segue per ogni metodi di overload in GAPP:

connect(&GApp::foo); 

chiamata a questo per foo() è ok, ma come posso chiamare questo per foo(double d)? Perché non funziona il seguente?

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

Mi darà

errore di sintassi: 'doppio' dovrebbe essere preceduto da ')'

Non capisco la sintassi che deve essere utilizzato qui. Questa potrebbe essere una stupida qustion, ma qualcuno può aiutarmi in questo?

+0

È un'idea migliore utilizzare i Functor invece dei puntatori di funzione imho. – Drakosha

+0

L'intero codice fa parte dell'implementazione di un meccanismo di Signal and Slot. Quindi, il litener (che ha lo slot) non vuole sapere del sistema. Quindi, non posso dire all'ascoltatore di fare così, fai così ...... – Morpheus

risposta

6

Il tuo codice come scritto non viene compilato. Ho fatto alcune "ipotesi" su ciò che volevi fare e ho cambiato il codice.

In sintesi, è possibile chiamare la funzione corretta specificando esplicitamente il tipo di parametro di funzione:

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

Se i metodi di connessione sono membri di un modello di classe, allora è necessario solo specificare il tipo di classe una volta :

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) 
} 

UPDATE:

in risposta alla nuova esempio di codice, tutto l'in la formazione viene inoltrata. Il caso "raro" è il caso "signal_void" in quanto questo è dove il segnale ha un argomento template, ma la funzione membro no. Quindi abbiamo un esempio speciale e poi abbiamo finito. Il seguente ora 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

Ehi! Grazie per lo sforzo. Scusa, ho dimenticato di dire che il mio codice non è completo. È stato perché ho rimosso la classe del modello Signal per semplificare il codice. A proposito, sì, il tuo metodo funziona bene. Pubblicherò il mio codice originale, puoi guardarlo allora? Grazie – Morpheus

+1

Wohooooo .... sì. Mi fai vedere il percorso. Ora tutto funziona correttamente. Grazie mille. – Morpheus

1

È possibile provare in modo esplicito la fusione il puntatore, per farle sapere quale scegliere, in questo modo:

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

disclaimer: non hanno testato

+0

Grazie per gli ans. Sì, funziona ... – Morpheus

+0

Non può essere sicuro: un cast è semplicemente una funzione sul puntatore GApp :: foo. Non cambierà il contenuto del puntatore. – xtofl

+0

Ho una teoria che è sicuro, vedere la mia risposta per i dettagli. Non l'ho ancora confermato nello standard, tuttavia, perché ho il forte sospetto che la lingua nello standard corrisponda comunque a Stroustrup's in C++ PL, ed è una domanda un po 'pacchiana. –

0

Questo è il lavoro,

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


    connect(MemberFunctionType); 

Perché è quello?

MODIFICA

hmm .. sì. È lo stesso della soluzione di newacct. Qualcuno può dare una soluzione pls?

+0

La mia risposta spiega il motivo per cui funziona, facendo riferimento a Stroustrup e un'ipotesi che ciò che dice sui puntatori di funzione si applica anche ai puntatori di funzioni dei membri. –

0

Utilizzando libreria di boost :: funzione ...

#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

Ehi! Grazie per gli ans. Non è il tuo (vuoto (GApp :: *) (doppio)) & GApp: foo; come la soluzione di newacct, (void (GApp :: *) (double)) & GApp :: foo. Ma xtofl ha detto che non è sicuro :( – Morpheus

+0

xtofl ha aggiornato il commento per dire che sembra essere sicuro: è preferibile usare gli oggetti funzione piuttosto che i puntatori di funzione, questo è tutto 1. – Anshul

0

Il mio codice originale è come questo,

connettori ....

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)); 
} 

Segnali ...

signal<double> signal_double; 
signal<> signal_void; 

applicazione ...

class GApp 
{ 
public: 
    void foo() {} 

    void foo(double d) {} 
}; 

Finaly, che collega ...

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

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

C'è modello classs per i segnali (che non sono menzionati qui). Spero che ora sia più chiara la situazione. (o è uguale a precedente?). Quella seconda connessione funzionerà se non c'è foo() (solo foo (double)). Questa è la cosa che mi ha ferito il mio codice. :(

5

Il C++ Programming Language, 3E, sezione 7.7, P159:.

Si può prendere l'indirizzo di una funzione sovraccaricata assegnando o inizializzazione di un puntatore a funzione In questo caso, il tipo di l'obiettivo viene utilizzato per selezionare dal set di funzioni sovraccaricate. ad esempio:

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) 

per quanto ne so (non ho controllato), lo stesso vale per le funzioni di membro Quindi la soluzione è probabilmente quella. diviso su due linee:

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

diventa:

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

Mai chiamano variabili tmp ;-)

Suppongo che il cast di newacct è sicuro troppo, esattamente per lo stesso motivo. La trasmissione su void (GApp::*)(double) è definita come l'inizializzazione di un valore temporaneo di tipo void (GApp::*)(double). Poiché l'espressione utilizzata per inizializzarlo è &GApp::foo, mi aspetto che la stessa magia si applichi al cast come si applica a qualsiasi altra inizializzazione con una funzione sovraccaricata. Stroustrup non dice "inizializzando una variabile puntatore-a-funzione", dice "inizializzando un puntatore-a-funzione". Quindi dovrebbe includere i provvisori.

quindi se si preferisce una battuta:

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

Tuttavia, sto supponendo che lo standard ha la stessa idea di coerenza come faccio io, e non ho controllato.

+0

THANKS! Ecco perché il cast funzionerà! – xtofl

+0

E dicono che il C++ è difficile da capire! ;-) –

Problemi correlati