2011-01-09 14 views
5

La "soluzione" di seguito viene compilata ma non è quello che voglio. Vorrei passare la funzione membro put a for_each e non a *this. L'utilizzo di boost è NON un'opzione. Può essere risolto in C++ 03?Passare una funzione membro a for_each in C++ 03 (senza 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

Potrebbe spiegare perché esattamente? – EmeryBerger

risposta

12

Sì è possibile, utilizzando una combinazione dei modelli mem_fun e bind1st:

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

La chiamata a mem_fun crea un nuovo oggetto funzione che prende in due argomenti - un Car* di agire come ricevitore e un Wheel, quindi chiama put con il primo parametro come destinatario e il secondo parametro come argomento. Se si chiama bind1st, l'oggetto destinatario viene bloccato come primo parametro di questa funzione.

Tuttavia, penso che sarà necessario apportare una piccola modifica a questo codice per farlo funzionare. L'adattatore bind1st non funziona bene con le funzioni che prendono i loro argomenti con riferimento const, quindi è necessario modificare put in modo che sia necessario un valore Wheel anziché per riferimento.

+0

Abbastanza sicuro che quelli siano solo in TR1, non in C++ 03. – Puppy

+1

@ DeadMG- No, quelli sono nella specifica da C++ 03. Il nuovo mem_fn che è un sostituto per questo è di gran lunga superiore, però. – templatetypedef

+1

@ Ali- Il motivo per cui non è possibile utilizzare un riferimento è che, internamente, il modello 'bind1st' tenta di prendere il suo argomento come riferimento a qualunque sia il tipo di argomento per la funzione originale. Se la funzione originale accetta un parametro per riferimento, prova a creare un riferimento a un riferimento, che non è consentito. Tuttavia, se il parametro è per puntatore, dovrebbe essere corretto; puoi avere un riferimento a un puntatore. – templatetypedef

1

Certo, puoi semplicemente scrivere il tuo equivalente di boost :: mem_func. Anche TR1 ne ha uno. È un po 'ripetitivo se si desidera un numero crescente di argomenti, ma non concettualmente difficile.

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

È passato un po 'di tempo da quando ho scritto un codice come questo, quindi potrebbe essere un po' spiacevole. Ma questo è il succo di ciò. È così difficile scrivere un esempio di utilizzo senza usare solo un lambda.

+0

Mi dispiace, non sono a questo livello. Puoi farmi un esempio? Quale dovrei usare e come? Grazie. – Ali

+0

@Ali: la riga fornita nel commento '// Usage' è un esempio dell'utilizzo. – Puppy

+0

Siamo spiacenti, ho perso l'ultima linea di utilizzo. Ho corretto due semplici errori di compilazione, ma dopo non riesco a correggere quelli rimanenti ... :( – Ali

3

È possibile utilizzare mem_fun_ref: vedere here.

mem_fun_ref dovrebbe funzionare nel vostro caso in cui si dispone di vettore di oggetti:

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

Si noti che l'esempio precedente cambia put di essere un membro della rotella e non auto. Dovrebbe darti un'idea di come usarlo comunque.

Usa mem_fun se si dispone di un vettore di puntatori a un oggetto

+0

Spiacente, questo non viene compilato. Si prega di notare che voglio Car :: put e non Wheel :: put come nell'esempio. (Ho provato a compilare con Car :: put.) – Ali

+0

Penso che questo potrebbe funzionare, ma tu ancora è necessario utilizzare bind1st come nella risposta di @ templatetypedef. –

+0

@Fred: Sì, funziona ma la risposta di templatetypedef è migliore perché funziona senza dover inserire una funzione membro di Wheel. – sashang

Problemi correlati