2015-09-18 18 views
6

Chcę zaimplementować mapę, która mapuje ciąg do ogólnego wektora.Mapa STL do generycznego wektora C++

chcę to zrobić:

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

Zakładając proponowane MyMap miał następującą włożona do niego, może być stosowany jako taki:

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> 

Kiedy Oświadczam mapę z powyższych Składnia kompilator ma atak serca.

Czy ktokolwiek może sugerować? Lub lepszą opcję tablicy asocjacyjnej w C++ (sugeruje brak wzmocnienia przed podbiciem).

+4

Będziesz potrzebować swoją wartość mapa być typu wariant, nie ma standardowy typ wariant więc musisz albo zaimplementować własne, albo użyć czegoś w rodzaju ['boost :: variant'] (http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html). – mattnewport

+0

Ile różnych "T" potrzebujesz do swojego std :: vector ? Możesz uciec z polimorficznym pojemnikiem, jeśli możesz dowiedzieć się, co przesłać za pośrednictwem RTTI lub za pośrednictwem jakiegoś identyfikatora, który sam sobie zaimplementowałeś. – VoidStar

+1

C++ jest statycznie wpisane, a typy wartości map muszą być takie same na mapie. Jeśli powiesz nam o prawdziwym problemie, który próbujesz rozwiązać, możemy być w stanie wskazać C++ - idiomatyczny sposób lub spojrzeć na 'boost :: variant'. –

Odpowiedz

2

Skoro znasz typ chcesz podczas pisania kodu, proponuję takie podejście (niesprawdzone):

// 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

Argumenty szablonów muszą być określone jako czas kompilacji. Jeśli chcesz, aby każdy klucz mapy odpowiadał wektorowi innego typu, to tak naprawdę nie zadziała. Możesz obejść to z polimorficznym pojemnikiem, który zwraca pustkę *, którą rzucasz do poprawnego typu, ale sugerowałbym próbę znalezienia innego sposobu zrobienia tego, co chcesz zrobić z twoją mapą.

+0

Polimorficzny pojemnik prawdopodobnie nie powinien zawierać zwrotu 'void *', ponieważ nie jest to sposób na ustalenie typu. Lepiej byłoby wymagać, aby sam kontener był upcastowany (przez przełącznik typu id lub identyfikator niestandardowy) do odpowiedniej podklasy, a następnie zwracany jest prawdziwy typ. – VoidStar

+0

Jeśli zwraca pustkę *, zakłada, że ​​dzwoniący wie, jaki typ zwraca. Bardzo niebezpieczne. Przypuszczam, że upcasting może być o wiele bezpieczniejszy. – fuzzything44

+0

to "ListOfInts" odnosi się tylko do wektora ? – ggrr

0

Może to może pracować dla Ciebie:

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

z C++ 11, można użyć using, robi dokładnie to, co chcesz:

#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

Dzięki za sugestię, ale nie jest to dokładnie to, co chcę zrobić. Nie chcę tworzyć więcej niż jednej instancji mapy, ale w jej ramach zapisuję wiele wektorów dowolnego typu. –

+0

Bez problemu ;-) Po ponownym przeczytaniu twojego pytania, myślę, że powinienem był sam to odkryć. Sądzę, że byłem zdezorientowany, ponieważ nie jest to typowy sposób C++. – alain

0

Jak powiedział mattnewport, jedną z opcji jest boost::variant.

Aby obsłużyć wszystkie typy, należy użyć boost::any, jawnie podając any_cast.

Biorąc pod uwagę zwiększenie obciążenia, może to być duża waga, może można odkryć nowe koło i uprościć je, aby nie było już więcej doładowania? lol