2010-10-15 13 views
11

la mia domanda è su come definire il modello nome di un membro della classe che dovrebbe essere utilizzato.Come modellare il nome della variabile NAMES, non i tipi?

Forse un semplificata & esempio pseudo:

/** 
Does something with a specified member of every element in a List. 
*/ 
template<membername MEMBER> // <-- How to define such thing? 
void doSomething(std::vector<MyClass> all){ 

    for(i=0; i < all.size(); i++) 
     all[i].MEMBER++; // e.g.; use all[i].MEMBER in same way 

} 

e

class MyClass{ 
public: 
    int aaa, bbb, ccc; 
} 

e l'applicazione:

main(){ 
    vector<MyClass> all = .... 

    // applicate doSomething() to all aaa's 
    doSomething<aaa>(all); // or: 
    doSomething<MyClass::aaa>(all); // or: 
    doSomething<?????>(all); 
} 

Come dovrebbe la definizione del modello sembra, che posso cambiare, che la variabile membro (aaa, bbb o ccc) di MyClass è accessibile/modificato in do Qualcosa(.) ?
Nel mio compito del mondo reale tutti i MEMBER sono dello stesso tipo, come sopra.

Grazie, Tebas

risposta

17

parametri template sono limitati a tipi, costanti intere, puntatori/riferimenti alle funzioni o oggetti con linkage esterno e puntatori utente - ma identificatori.

Ma si potrebbe usare un puntatore membro come parametro di modello:

template<int MyClass::* MemPtr> 
void doSomething(std::vector<MyClass> & all) { 
    for(i=0; i < all.size(); i++) 
     (all[i].*MemPtr)++; 
} 

: 

doSomething<&MyClass::aaa>(all); 

Nota che ho cambiato la funzione doSomething di prendere un punto di riferimento invece di accettare il vettore per valore.

+0

Grazie. Chiamare "tutto" in base al valore era per la semplificazione della domanda ... ma è una chiamata per riferimento richiesta dai modelli di puntatore membri? o posso anche usare una copia? – Tebas

+0

@Tebas: è possibile utilizzare una copia, ma ciò significa che l'effetto di 'doSomething' non sarà visibile al di fuori della funzione. La chiamata per riferimento è stata utilizzata per garantire che il risultato fosse visibile nel vettore del chiamante. –

+0

@Tebas: No, non fa alcuna differenza. In entrambi i casi tutto [i] sarà un'espressione lvalue di tipo MyClass. – sellibitze

1

Vorrei utilizzare lambda per risolvere questo problema. Qualcosa di simile a questo:

#include <vector>  // vector 
#include <algorithm> // for_each 
#include <functional> // function 

struct MyClass { 
    void func1() const { std::cout << __FUNCTION__ << std::endl; } 
    void func2() const { std::cout << __FUNCTION__ << std::endl; } 
}; 

void doSomething(std::vector<MyClass> all, std::function<void (MyClass& m)> f) 
{ 
    std::for_each(all.begin(), all.end(), f); 
} 

int main() 
{ 
    std::vector<MyClass> all; 
    all.push_back(MyClass()); 

    // apply various methods to each MyClass: 
    doSomething(all, [](MyClass& m) { m.func1(); }); 
    doSomething(all, [](MyClass& m) { m.func2(); }); 
} 

Naturalmente, in questo caso la funzione doSomething non è necessaria. Potrei semplicemente chiamare lo for_each direttamente su all.

10

soluzione sellibitze va bene (anche se onestamente non molto: vedere la mia modifica), solo si limita a utilizzare solo membri di tipo int. Una soluzione più generale sarebbe questo (anche se l'utente non è un parametro di template qui)

#include <vector> 

struct MyClass 
{ 
    int i; 
    char c; 
}; 

template <class T> 
void DoSomething(std::vector<MyClass>& all, T MyClass::* MemPtr) 
{ 
    for(std::vector<MyClass>::size_type i = 0; i < all.size(); ++i) 
     (all[i].*MemPtr)++; 
} 

int main() 
{ 
    std::vector<MyClass> all; 
    DoSomething(all, &MyClass::i); 
    DoSomething(all, &MyClass::c); 
} 

EDIT: Inoltre si prega di notare che non è generalmente una buona idea per un puntatore a membro ad essere una misura in parametro di modello come è possibile passare solo i puntatori noti in fase di compilazione, ovvero non è possibile determinare il runtime del puntatore e quindi passarlo come parametro del modello.

+0

' vector :: all() 'restituisce' size_t' e non 'unsigned' - per favore usa' size_t' per 'i'. (Iterators sarebbe ancora meglio ... –

+1

@Steve: Sono completamente d'accordo sugli iteratori, ho appena copiato il testo dal codice dell'op. Non cambierò quello. E size() NON restituisce size_t, restituisce std :: vector :: size_type. è vector :: all?: D –

+0

Oops, hai ragione sul punto 1 e non so cosa stavo pensando al punto 2. +1 per te. Stranamente, ho * risposto * una domanda relativa ai vettori e Sapevo di usare 'size_type' e non' size_t'. A volte sono cattivo. –

Problemi correlati