2012-05-13 8 views
5

Sto usando la seguente struct come input per generate_n algoritmo di STL:di Functor non viene mantenuta tra chiamate consecutive a generate_n

struct GenerateNumber {  
    GenerateNumber() : i(0) {} 
    int operator() (void) {   
     return i++; 
    } 
private: 
    int i; 
}; 

Un esempio per il codice che utilizza questo funtore è:

std::vector <int> v1 (3); 
std::vector <int> v2 (3); 
GenerateNumber generateNumber; 
std::generate_n (v1.begin(), 3, generateNumber); 
std::generate_n (v2.begin(), 3, generateNumber); 

Tuttavia, il risultato è che sia v1 e v2 contengono {0,1,2}, anziché v2 per contenere {3,4,5}. Ho verificato con un breakpoint che il costruttore di GenerateNumber viene chiamato una sola volta (so che non ha senso che il costruttore sia chiamato più di una volta, ma l'ho verificato comunque).

So che posso risolvere questo rendendo statico i, ma non capisco questo comportamento. Come mai il valore di i non viene mantenuto tra le chiamate consecutive?

risposta

8

L'oggetto generatore viene copiato quando passato a generate_n. Provare a utilizzare std::ref, vale a dire

std::generate_n(v1.begin(), 3, std::ref(generateNumber)); 
std::generate_n(v2.begin(), 3, std::ref(generateNumber)); 

Edit: noti che std::ref è disponibile soltanto in C++ 11. È stato introdotto in TR1 come std::tr1::ref ed è anche disponibile in boost come boost::ref.

+0

È dovrei ricordare che 'std :: ref' è C++ 11 (anche se è menzionato anche in TR1). –

+0

Probabilmente dovrò stare con la soluzione 'static', dato che ho bisogno del mio codice per compilare sia in VS2010 (che implementa C++ 11) che GCC 4.4 (che non lo fa). Tuttavia, solo per la completezza, quando uso il tuo suggerimento ottengo il seguente errore di compilazione: 'errore C2679: binario '=': nessun operatore trovato che prende un operando di destra di tipo 'void' (o non c'è conversione accettabile) \t C: \ Programmi (x86) \ Microsoft Visual Studio 10.0 \ VC \ include \ algorithm \t 1581' –

+0

@LucDanton: Grazie per la nota. A volte dimentico che c'è stato un tempo prima del C++ 11. – nosid

3

std::generate_n prende il funtore in base al valore, cioè ne fa una copia. Potrebbe essere che non hai controllato che il costruttore di copie fosse chiamato.

In assenza di std::ref, e se il problema è localizzato come nel tuo esempio, è possibile modificare la functor a prendere un riferimento ad un contatore impostato nel campo di applicazione delle chiamate per std::generate_n:

struct GenerateNumber {  
    GenerateNumber (int& i) : struct GenerateNumber {  
    GenerateNumber() : i(0) {} 
    int operator() (void) {   
     return i++; 
    } 
private: 
    int& i; 
}; 

int main() { 
    int counter = 0; 
    std::vector <int> v1 (3); 
    std::vector <int> v2 (3); 
    GenerateNumber generateNumber(counter); 
    std::generate_n (v1.begin(), 3, generateNumber); 
    std::generate_n (v2.begin(), 3, generateNumber); 

} 
+0

Grazie, questa è una soluzione elegante. –

Problemi correlati