2015-09-18 9 views
6

Ich möchte eine Map implementieren, die einen String einem generischen Vektor zuordnet.STL-Map zu generischem Vektor C++

Ich möchte, dies zu tun:

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

die vorgeschlagene myMap Unter der Annahme, hatte die in sie eingefügt folgenden, könnte es als solches verwendet werden:

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> 

Wenn ich erklären die Karte mit dem oben Syntax der Compiler hat einen Herzinfarkt.

Kann jemand irgendwelche Vorschläge machen? Oder eine bessere assoziieren Array-Option in C++ (vorschlagen, Nicht-Boost vor Boost).

+4

Sie Ihre Karte Wert benötigen würde ein Variant-Typ zu sein, gibt es keine Standardvariante Typ Sie müssten also entweder Ihre eigenen implementieren oder etwas wie ['boost :: variant'] (http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html) verwenden. – mattnewport

+0

Wie viele verschiedene 'T' brauchen Sie für Ihren std :: vector ? Sie könnten mit einem polymorphen Container davonkommen, wenn Sie herausfinden können, worüber Sie über RTTI oder über eine Art von ID, die Sie selbst implementieren, zu sprechen haben. – VoidStar

+1

C++ ist statisch typisiert und Map-Werttypen müssen in einer Map alle gleich sein. Wenn Sie uns das wirkliche Problem mitteilen, das Sie zu lösen versuchen, können wir in der Lage sein, auf C++ - idiomatisch zu verweisen, oder auf "boost :: variant" zu schauen. –

Antwort

2

Da Sie den Typ, den Sie wollen wissen, wann Sie Ihren Code schreiben, ich diesen Ansatz (ungetestet) vorschlagen:

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

Template-Argumente müssen Kompilierungszeit entschieden werden. Wenn Sie möchten, dass jeder Schlüssel Ihrer Map einem Vektor eines anderen Typs entspricht, wird er nicht wirklich funktionieren. Sie können es mit einem polymorphen Container umgehen, der ein void * zurückgibt, das Sie in den richtigen Typ umgewandelt haben, aber ich würde vorschlagen, dass Sie versuchen, einen anderen Weg zu finden, was Sie zuerst mit Ihrer Karte machen wollen.

+0

Der polymorphe Container sollte wahrscheinlich nicht return 'void *' enthalten, da dies keine Möglichkeit bietet herauszufinden, um welchen Typ es sich handelt. Besser wäre es, zu verlangen, dass der Container selbst (über einen Schalter typid oder eine benutzerdefinierte ID) in die entsprechende Unterklasse versetzt wird und dann der echte Typ zurückgegeben wird. – VoidStar

+0

Wenn ein void * zurückgegeben wird, wird davon ausgegangen, dass der Anrufer weiß, welchen Typ er zurückgibt. Sehr unsicher. Ich denke, dass Upcasting viel sicherer sein könnte. – fuzzything44

+0

ist "ListOfInts" bezieht sich nur auf Vektor ? – ggrr

0

Vielleicht könnte dies für Sie arbeiten:

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

Mit C++ 11, Sie using verwenden können, es tut genau das, was Sie wollen:

#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

Danke für den Vorschlag, aber das ist nicht ganz das, was ich tun möchte. Ich möchte nicht mehr als eine Instanz der Karte erstellen, aber darin mehrere Vektoren jeden Typs speichern. –

+0

Kein Problem ;-) Nachdem ich deine Frage nochmal gelesen habe, denke ich, ich hätte das selbst herausfinden sollen. Ich glaube, ich war verwirrt, weil es kein typischer C++ - Weg ist. – alain

0

Wie Mattnewport sagte boost::variant ist eine Option.

Oder um alle Typen zu unterstützen, verwenden Sie boost::any explizit mit any_cast.

Wenn man bedenkt, dass der Boost ein schweres Gewicht sein kann, können Sie das Rad vielleicht neu erfinden und es vereinfachen, so dass es keinen Boost mehr gibt? lol