2011-01-09 18 views
5

La "solución" a continuación se compila pero no es lo que quiero. Me gustaría pasar la función de miembro put a for_each y no a *this. El uso de boost es NOT una opción. ¿Se puede resolver esto dentro de C++ 03?Pasar una función miembro a for_each en C++ 03 (no boost, no C++ 11)

#include <algorithm> 
#include <functional> 
#include <vector> 
using namespace std; 

class Wheel { }; 

class Car { 

public: 

    void process(const vector<Wheel>& wheel) { 

     for_each(wheel.begin(), wheel.end(), *this); 
    } 

    void operator()(const Wheel& w) { put(w); } 

private: 

    void put(const Wheel& w) { } 
}; 

int main() { 

    vector<Wheel> w(4); 

    Car c; 

    c.process(w); 

    return 0; 
} 
+0

Podría explicar por qué exactamente? – EmeryBerger

Respuesta

12

Sí se puede, usando una combinación de las plantillas mem_fun y bind1st:

void process(const vector<Wheel>& wheel) { 
    for_each(wheel.begin(), wheel.end(), bind1st(mem_fun(&Car::put), this)); 
} 

La llamada a mem_fun crea un nuevo objeto función que toma dos argumentos - una Car* para actuar como receptor y un Wheel, luego llama al put con el primer parámetro como el receptor y el segundo parámetro como el argumento. Llamar al bind1st luego bloquea el objeto receptor como primer parámetro de esta función en su lugar.

Sin embargo, creo que deberá hacer un pequeño cambio en este código para que funcione. El adaptador bind1st no funciona bien con funciones que toman sus argumentos por referencia constante, por lo que podría necesitar cambiar put para que tome Wheel por valor en lugar de por referencia.

+0

Bastante seguro de que esos solo están en TR1, no en C++ 03. – Puppy

+1

@ DeadMG- No, esos están en la especificación de C++ 03. Sin embargo, el nuevo mem_fn que es un reemplazo para él es muy superior. – templatetypedef

+1

@ Ali- La razón por la que no puede usar una referencia es que, internamente, la plantilla 'bind1st' intenta tomar su argumento como referencia a cualquier tipo de argumento para la función original. Si la función original toma un parámetro por referencia, esto intenta crear una referencia a una referencia, que no está permitido. Sin embargo, si el parámetro es por puntero, eso debería estar bien; puedes tener una referencia a un puntero. – templatetypedef

1

Claro que puedes escribir tu propio equivalente de boost :: mem_func. TR1 tiene uno también. Es un poco repetitivo si quieres un número creciente de argumentos, pero no conceptualmente difíciles.

template<typename T, typename mem_func_type> struct mem_func_internal; 
template<typename T, typename Ret> struct mem_func_internal<T, Ret (T::*)()> { 
    typedef Ret(T::* functype)(); 
    T* obj; 
    functype func; 
    Ret operator()() { 
     return obj->*func(); 
    } 
}; 
template<typename T, typename Ret, typename ArgType1> struct mem_func_internal<T, Ret (T::*)(ArgType1) { 
    typedef Ret(T::* functype)(); 
    T* obj; 
    functype func; 
    Ret operator()(ArgType1 arg) { 
     return obj->*func(arg); 
    } 
} 
template<typename T, typename mem_func_type> struct mem_func : public mem_func_internal<T, mem_func_type> { 
    mem_func(T* object, mem_func_type mem_func) 
     : obj(object) 
     , func(mem_func) {} 
}; 
template<typename T, typename mem_func_type> mem_func<T, mem_func_type> bind_mem_func(T* object, mem_func_type func) { 
    return mem_func<T, mem_func_type>(object, func); 
} 
// Usage 
std::for_each(wheel.begin(), wheel.end(), bind_mem_func(this, &Car::put)); 

Ha pasado un tiempo desde que escribí código como este, por lo que podría estar un poco apagado. Pero esa es la esencia de eso. Es tan difícil escribir un ejemplo de uso sin solo usar una lambda.

+0

Lo siento, no estoy en este nivel. ¿Podrías darme un ejemplo? ¿Cuál debería usar y cómo? Gracias. – Ali

+0

@Ali: la línea dada bajo el comentario '// Usage' es un ejemplo del uso. – Puppy

+0

Lo siento, me perdí la última línea de uso. Repare dos errores de compilación sencillos, pero después de eso no puedo corregir los restantes ... :( – Ali

3

Puede usar mem_fun_ref: vea here.

mem_fun_ref debe trabajar en su caso en el que usted tiene el vector de objetos:

for_each(wheel.begin(), wheel.end(), mem_fun_ref(&Wheel::put)); 

Tenga en cuenta que el ejemplo anterior cambia put a ser miembro de la rueda y no coches. Sin embargo, debería darle una idea de cómo usarlo.

Uso mem_fun si tiene un vector de punteros a un objeto

+0

Disculpe, esto no se compila. Tenga en cuenta que quiero Car :: put y no Wheel :: poner como en el ejemplo. (Intenté compilar con Car :: put.) – Ali

+0

Creo que esto podría funcionar, pero aún así Necesito usar bind1st como en la respuesta de @ templatetypedef. –

+0

@Fred: Sí, funciona, pero la respuesta de templatetypedef es mejor porque funciona sin tener que hacer una función miembro de Wheel. – sashang

Cuestiones relacionadas