2015-09-18 25 views
6

Voglio implementare una mappa, che mappa una stringa in un vettore generico.STL map to generic vector C++

Voglio fare questo:

std::map<std::string, std::vector<class T> > myMap; 

Supponendo che il myMap proposto aveva le seguenti inserito in esso, potrebbe essere usato come tale:

vector<int> intVec = myMap["ListOfInts"]; // Works because "ListOfInts" maps to a vector<int> 
vector<string> stringVec = myMap["ListOfStrings"]; // Works because "ListOfInts" maps to a vector<string> 

Quando dichiaro la mappa con quanto sopra sintassi il compilatore ha un attacco di cuore.

Qualcuno può dare qualche suggerimento? O una migliore opzione di array associato in C++ (suggerire non-boost prima di aumentare).

+4

si avrebbe bisogno il vostro valore di carta per essere un tipo di variante, non c'è alcun tipo di versione standard quindi dovresti implementare il tuo o usare qualcosa come ['boost :: variant'] (http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html). – mattnewport

+0

Quanti '' T' necessari per il tuo std :: vector ? Potresti farla franca con un contenitore polimorfico se riesci a capire che cosa trasmettere a RTTI o tramite qualche tipo di ID da te implementato. – VoidStar

+1

Il C++ è tipizzato in modo statico e i tipi di valori della mappa devono essere tutti uguali in una mappa. Se ci dici il vero problema che stai cercando di risolvere, potremmo essere in grado di indicare un C++ - modo idiomatico, o guardare 'boost :: variant'. –

risposta

2

Dal momento che si conosce il tipo che si desidera quando si sta scrivendo il codice, propongo questo approccio (non testata):

// base class for any kind of map 
class BaseMap { 
public: 
    virtual ~BaseMap() {} 
}; 

// actual map of vector<T> 
template<typename T> 
class MapT : public BaseMap, public std::map<std::string, std::vector<T>> {}; 

class MultiMap { 
public: 
    template<typename T> 
    std::vector<T>& get(const std::string& key) { 
    std::unique_ptr<BaseMap>& ptr = maps_[std::type_index(typeid(T))]; 
    if (!ptr) ptr.reset(new MapT<T>()); 
    return ptr->second[key]; 
    } 
private: 
    std::map<std::type_index, std::unique_ptr<BaseMap>> maps_; 
} 

int main() { 
    MultiMap map; 
    std::vector<int>& intVec = map.get<int>("ListOfInts"); 
    std::vector<std::string>& stringVec = map.get<std::string>("ListOfStrings"); 
} 
-2

Gli argomenti del modello devono essere decisi in fase di compilazione. Se vuoi che ogni chiave della tua mappa corrisponda a un vettore di un tipo diverso, non funzionerà davvero. Puoi aggirare il problema con un contenitore polimorfico che restituisce un vuoto * che hai lanciato sul tipo corretto, ma ti suggerirei di provare a trovare un altro modo per fare prima quello che vuoi fare con la tua mappa.

+0

Probabilmente il contenitore polimorfico non conterrà il valore restituito 'void *', poiché ciò non fornisce un modo per capire di che tipo si tratta. Sarebbe meglio richiedere che il contenitore stesso venga aggiornato (tramite un commutatore su typeid o un id personalizzato) alla sottoclasse appropriata e che venga restituito il tipo reale. – VoidStar

+0

Se restituisce un void *, presuppone che il chiamante sappia quale tipo restituisce. Molto pericoloso Suppongo che l'upcasting potrebbe essere molto più sicuro. – fuzzything44

+0

è "ListOfInts" si riferisce solo al vettore ? – ggrr

0

Forse questo potrebbe funzionare per voi:

template <typename T> 
class MyMap { 
    std::map<std::string, std::vector<typename T> > map; 
public: 
    /*...*/ 
}; 
0

Con C++ 11, è possibile utilizzare using, fa esattamente ciò che si vuole:

#include <vector> 
#include <map> 
#include <string> 

template<typename T> using mymap = std::map<std::string, std::vector<T>>; 

int main() 
{ 
    mymap<int> intmap; 
    mymap<std::string> stringmap; 

    std::vector<int> intvec = intmap["test"]; 
    std::vector<std::string> stringvec = stringmap["test"]; 

    return 0; 
} 

Live Demo

+0

Grazie per il suggerimento, ma questo non è esattamente quello che cerco di fare. Non voglio creare più di un'istanza della mappa, ma al suo interno memorizza più vettori di qualsiasi tipo. –

+0

Nessun problema ;-) Dopo aver letto di nuovo la tua domanda, penso che avrei dovuto scoprirlo da solo. Credo di essere stato confuso perché non è un tipico modo C++ per farlo. – alain

0

Come mattnewport ha detto che boost::variant è un'opzione.

Oppure per supportare qualsiasi tipo, utilizzare boost::any utilizzando esplicitamente any_cast.

Considerare il boost potrebbe essere pesante, forse è possibile reinventare la ruota e semplificarla, quindi non è più un boost? lol