2009-12-11 4 views
6

Ho bisogno di chiamare un metodo che si aspetta un puntatore a funzione, ma quello che voglio veramente passare ad esso è un functor. Ecco un esempio di quello che sto cercando di fare:Funzione di puntatori alle funzioni membro in C++

#include <iostream> 
#include "boost/function.hpp" 

typedef int (*myAdder)(int); 

int adderFunction(int y) { return(2 + y); } 

class adderClass { 
    public: 
    adderClass(int x) : _x(x) {} 
    int operator() (int y) { return(_x + y); } 

    private: 
    int _x; 
}; 

void printer(myAdder h, int y) { 
    std::cout << h(y) << std::endl; 
} 

int main() { 
    myAdder f = adderFunction; 

    adderClass *ac = new adderClass(2); 
    boost::function1<int, int> g = 
    std::bind1st(std::mem_fun(&adderClass::operator()), ac); 

    std::cout << f(1) << std::endl; 
    std::cout << g(2) << std::endl; 
    printer(f, 3); 
    printer(g, 4); // Is there a way to get this to work? 
} 

non sono stato in grado di trovare un modo per ottenere l'ultima riga, una stampante (g, 4), per la compilazione. C'è un modo per farlo funzionare? Le uniche cose a mio controllo sono il metodo "main" e la classe "adderClass".

risposta

0

in questo modo:

template<typename AdderT> 
void printer(AdderT h, int y) { 
    std::cout << h(y) << std::endl; 
} 

Inoltre, non è necessario il boost::function. Basta fare:

adderClass ac(2); 
    std::cout << f(1) << std::endl; 
    std::cout << ac(2) << std::endl; 
    printer(f, 3); 
    printer(ac, 4); 
+0

Che funzionerebbe, ma (ho dimenticato di menzionare), il metodo "stampante" è in codice che non posso cambiare. – JamieC

+0

Tutto ciò che è nel mio controllo è il metodo "main" e la classe "adderClass". – JamieC

0

Mentre una funzione di boost si comporta come un normale puntatore a funzione, è un tipo diverso. Quindi non puoi semplicemente assegnare una funzione boost a un puntatore di funzione.

Nel codice si può semplicemente sostituire

typedef int (*myAdder)(int); 

con

typedef boost::function1< int, int > myAdder; 

e tutto avrebbe funzionato.

2

Ok, qui è un altro tentativo:

class CallProxy 
{ 
public: 
    static adderClass* m_instance; 
    static int adder(int y) 
    { 
     return (*m_instance)(y); 
    } 
}; 

adderClass* CallProxy::m_instance = NULL; 


int main() { 
    myAdder f = adderFunction; 

    adderClass ac(2); 

    std::cout << f(1) << std::endl; 
    std::cout << ac(2) << std::endl; 
    printer(f, 3); 
    CallProxy::m_instance = &ac; 
    printer(CallProxy::adder, 4); 
} 

Il guaio è che avete printer compilato come avere a ricevere un puntatore a funzione e nient'altro quindi è necessario inviare un puntatore a funzione. Con un puntatore a funzione non hai nessuno con cui tenere la tua istanza. Quindi questa soluzione lo fa usando un membro di dati statici.

Ricorda che questo rende questo codice non sicuro. Due thread che eseguono main allo stesso tempo possono mettere due cose diverse in m_instance.

+1

Non è neanche rientrante: se 'printer' chiama' main' sei nei guai. Ma penso che sia il meglio che si possa fare considerando i vincoli, almeno in termini di portabilità. Per soluzioni non portatili, potresti ad esempio generare codice al volo. –

+0

@Steve Jessop: Qualsiasi cosa che chiama 'main()' causa comunque un comportamento indefinito (§3.6.1/2: "La funzione main non deve essere utilizzata (3.2) all'interno di un programma.") –

+0

@Jerry Coffin - provate a guarda oltre i confini limitati di questo stupido esempio. – shoosh