2012-03-30 16 views
15

ja inicjowanie map<string, vector<string> > następująco:inicjalizacji map <string, wektor <string>>

map <string, vector<string> > dict; 

dict["USA"].push_back("NYC"); 
dict["USA"].push_back("LA"); 
dict["USA"].push_back("Chicago"); 
dict["USA"].push_back("Dallas"); 

dict["India"].push_back("Delhi"); 
dict["India"].push_back("Bombay"); 

dict["Australia"].push_back("Melbourne"); 
dict["Australia"].push_back("Sydney"); 
dict["Australia"].push_back("Adelaide"); 

znajdę to uciążliwe. To samo można zrobić w tcl następująco który jest czystsze:

array set dict { 
USA {NYC LA Chicago Dallas} 
India {Delhi Bombay} 
Australia {Melbourne Sydney Adelaide} 
} 

Czy jest bardziej przejrzysty sposób można zainicjować w C++? Mój kompilator jest gcc 3.4.6

+7

W C++ 11, tak. W GCC 3.4.6, nie. – Pubby

+2

GCC 3.4.6 ??? Naprawdę powinieneś rozważyć uaktualnienie do nowszego kompilatora ... Istnieje biblioteka doładowania, aby ułatwić ten typ inicjalizacji, ale nie jestem pewien, czy można go użyć z takim starym kompilatorem (6 lat to prawie wieczność) –

Odpowiedz

6

Jeśli nie boisz się używać makr w stylu C i niektórych konstrukcji pomocniczych, możesz uznać to za nieco mniej drażliwe; inicjalizacja mapy odbywa się w jednym wierszu; musisz tylko wypełnić dane (które i tak musisz zrobić).

#include <iostream> 
#include <map> 
#include <vector> 
#include <string> 
#include <utility> 

using namespace std; 

struct entry { 
    string key; 
    string* vals; 
    size_t nvals; 
}; 
#define NVAL(x) (sizeof(x)/sizeof(x[0])) 

int main(void) { 
    // Create your data 
    string  usa[]  = {"NYC", "LA"}; 
    string  india[] = {"Delhi", "Mumbai"}; 
    entry  dd[] = { 
          {"USA", usa, NVAL(usa)}, 
          {"India", india, NVAL(india)} 
         }; 
    map<string, vector<string> > dict; 

    // initialize the map 
    for(unsigned int i=0; i<NVAL(dd); i++) 
     dict.insert(make_pair(dd[i].key, vector<string>(dd[i].vals, dd[i].vals+dd[i].nvals))); 

    // Verify 
    for(map<string,vector<string> >::const_iterator ptr=dict.begin(); 
     ptr!=dict.end(); ptr++) { 
     cout << ptr->first << ": "; 
     for(vector<string>::const_iterator eptr=ptr->second.begin(); 
      eptr!=ptr->second.end(); eptr++) 
       cout << *eptr << " "; 
     cout << endl; 
    } 
    return 0; 
} 
+0

Twoje makro może być trywialnie zastąpione szablonem funkcji: 'template std :: size_t NVAL (T (&) [N]) {return N; } '. – ildjarn

+0

To rzeczywiście jest eleganckie rozwiązanie! Dzięki! – haavee

25

Inicjalizacja miała wiele ograniczeń w starym C++. Twój kod w rzeczywistości niczego nie inicjuje; po prostu wywołuje wiele funkcji składowych na już zainicjowanym obiekcie.

W bieżącym C++ (C++ 11) Państwo może zainicjować swoją mapę prawidłowo:

std::map<std::string, std::vector<std::string>> const dict { 
    { "USA", { "NYC", "LA", "Chicago" } }, 
    { "India", { "Delhi", "Bombay" } } 
}; 
+4

o Boże, to jest piękne! – innochenti

+2

To naprawdę szkoda, że ​​zajęło im to ~ 15 lat: P – haavee

+0

O, a OP powiedział, że jego kompilatorem jest g ++ 3.4.6, co jest bardzo dalekie od C++ 11 - więc zamieszczanie eleganckich rozwiązań, które OP nie może użyć może nie być tak pomocne ... niestety. – haavee

8

Można to zrobić, jeśli C++ 11 nie jest dostępny:

map <string, vector<string> > dict; 

string usa[] = { "NYC" , "LA" , "Chicago" , "Dallas" }; 
dict["USA"] = std::vector<string>(usa,usa+4); 
8

Jeśli nie jesteś przeciwny używaniu biblioteki Boost.Assign i używasz C++ starszego niż C++ 11, możesz to zrobić tak:

#include <boost/assign/list_of.hpp> 
#include <boost/assign/std/vector.hpp> 
#include <map> 
#include <string> 
#include <vector> 

std::map<std::string, vector<std::string> > dict = boost::assign::map_list_of<std::string, std::vector<std::string> > 
    ("USA", boost::assign::list_of<std::string>("NYC")("LA")("Chicago")("Dallas")) 
    ("India", boost::assign::list_of<std::string>("Delhi")("Bombay")) 
; 
Powiązane problemy