2009-12-11 12 views
6

Necesito llamar a un método que espera un puntero de función, pero lo que realmente quiero pasar es un funtor. He aquí un ejemplo de lo que estoy tratando de hacer:Punteros de función para funciones de miembro en 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? 
} 

no he sido capaz de encontrar una manera de conseguir la última línea, la impresora (g, 4), para compilar. ¿Hay alguna manera de hacer que esto funcione? Las únicas cosas bajo mi control son el método "main" y la clase "adderClass".

Respuesta

0

así:

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

Además, no es necesario el boost::function. Puede hacerlo:

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

Eso funcionaría, pero (olvidé mencionar), el método "impresora" está en el código que no puedo cambiar. – JamieC

+0

Todo lo que está bajo mi control es el método "main" y la clase "adderClass". – JamieC

0

Si bien una función de refuerzo se comporta como un puntero de función normal, es de un tipo diferente. Por lo tanto, no puede asignar una función de impulso a un puntero de función.

En su código simplemente podría reemplazar

typedef int (*myAdder)(int); 

con

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

y todo iba a funcionar.

2

Ok, aquí hay otra oportunidad:

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

El problema es que usted tiene printer compilado como tener que recibir un puntero a función y nada más por lo que debe enviar un puntero de función. Con un puntero de función no tiene a nadie para mantener su instancia. Entonces esta solución hace eso al usar un miembro de datos estáticos.

Tenga en cuenta que esto hace que este código no sea seguro para subprocesos. Dos hilos que ejecutan main al mismo tiempo pueden poner dos cosas diferentes en m_instance.

+1

Tampoco es reentrante: si 'printer' llama' main', tiene problemas. Pero creo que es lo mejor que se puede hacer dadas las limitaciones, al menos de manera portátil. Para soluciones no portátiles, podría, por ejemplo, generar código sobre la marcha. –

+0

@Steve Jessop: Cualquier cosa que llame 'main()' provoca un comportamiento indefinido de todos modos (§3.6.1/2: "La función main no se usará (3.2) dentro de un programa.") –

+0

@Jerry Coffin - intente mira más allá de los límites limitados de este ejemplo tonto. – shoosh

Cuestiones relacionadas