2009-11-11 14 views
10

Quando lavoro con BOOST_FOREACH, non c'è un problema con i modelli semplici come vettore. Ma quando provo ad iterare attraverso la mappa> per esempio ho bisogno di digitare il tipo di elemento.BOOST_FOREACH e modelli senza typedef

C'è qualche soluzione?

risposta

12

C'è un problema perché è una macro e quindi non può gestire tipi contenenti virgole (il preprocessore non conosce i modelli).

È inoltre possibile dichiarare la variabile prima del ciclo, vedere documentation.

std::map<int, double> my_map; 

//1) 
typedef std::pair<int, double> MyPair; 
BOOST_FOREACH(MyPair p, my_map) { ... } 

//2) 
std::pair<int, double> p; 
BOOST_FOREACH(p, my_map) { ... } 

Edit:

V'è un ulteriore complicazione con std::map in particolare: la value_type non è std::pair<Key, Value>, ma std::pair<const Key, Value>.

Quindi, se si va con il typedef, un modo più corretto (e l'unico modo se si desidera utilizzare un di riferimento nel ciclo foreach) è quello di utilizzare

typedef std::pair<const int, double> MyPair; 
//or 
typedef std::map<int, double>::value_type MyPair; 

BOOST_FOREACH(MyPair& ref, my_map) { ... } 

Tuttavia, che ha vinto funziona se si desidera utilizzare una variabile dichiarata prima del ciclo, poiché non è possibile assegnare successivamente un'istanza std::pair<const int, double> (impossibile assegnare al campo const), nel qual caso è possibile utilizzare solo pair<int, double> come illustrato dal manuale di boost.

+1

probabilmente si dovrebbe fare questo: STD :: mappa :: value_type –

+0

anche in C++ 11; BOOST_FOREACH (auto & ref, my_map) {...} –

8

Se avete bisogno di iterare su una mappa, il modo più semplice è quello di utilizzare tuple, dal momento che ricevendo il corretto digitare per digitare, è problematico. Ecco come è possibile utilizzare le tuple:

std::map<int, double> my_map; 
int key; 
double value; 
BOOST_FOREACH(boost::tie(key, value), my_map) { ... } 

Solo una nota, le virgole lavorerà qui perché le parentesi sono collocati intorno chiave e valore. Il preprocessore comprende solo virgole e parentesi (e c99 richiede di comprendere anche le virgolette). Quindi, non può analizzare lo <> in std::pair<int, double>. Tuttavia, possiamo usare le parentesi per aiutare il preprocessore. Per esempio, se abbiamo aa funzione che restituisce un contenitore che si chiama in questo modo:

BOOST_FOREACH(int i, foo<int, int>()) { ... } //This won't compile 

Quindi, possiamo mettere parentesi intorno un'espressione e aiuterà il preprocessore:

BOOST_FOREACH(int i, (foo<int, int>())) { ... } //This will compile 

Tuttavia, nel caso di una mappa, non possiamo collocare la parentesi attorno alla dichiarazione (perché non è un'espressione). Quindi questo non funziona:

BOOST_FOREACH((std::pair<int, double> p), my_map) { ... } //This won't work 

Perché sarà ottenere trasformato in qualcosa di simile (std::pair<int, double> p) = *it, e che, naturalmente, non è corretta C++.Ma utilizzando una cravatta funzionerà:

BOOST_FOREACH(tie(key, value), my_map) { ... } //This will work 

Abbiamo solo bisogno di dichiarare chiave e valore al di fuori del ciclo (come mostrato sopra). Inoltre, può far sì che il loop abbia nomi più significativi. È possibile scrivere key anziché p.first e value anziché p.second.

+0

La virgola tra chiave e valore confonderà il preprocessore. – Ferruccio

+0

@Ferruccio La virgola tra chiave e valore *** NON *** confonderà il preprocessore a causa della parentesi attorno a chiave e valore. Inoltre, lo faccio sempre quando ho bisogno di iterare una mappa. –

+0

Non avevo idea che potessi farlo con il preprocessore. – Ferruccio

2

Questo può essere semplice come questo:

BOOST_FOREACH(auto& p, my_map) { ... } 

Utilizzando lo standard C++ 11, auto è come var in C#, lo farà

BOOST_FOREACH(std::pair<int, double>& p, my_map) { ... }