2015-09-18 2 views
6

Я хочу реализовать карту, которая отображает строку в общий вектор.STL map to generic vector C++

Я хочу, чтобы это сделать:

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

Предполагая, что предложенный MyMap имел следующий вставленный в него, он может быть использован как таковой:

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> 

Когда я объявляю карту с вышеизложенным Синтаксис компилятора имеет сердечный приступ.

Можно ли сделать какие-либо предложения? Или вариант более подходящего массива в C++ (предположим, что он не повышается до повышения).

+4

Вы должны были бы ваши ценности карты быть вариантом типа, нет стандартного типа варианта так что вам придется либо реализовать свои собственные, либо использовать что-то вроде [boost :: variant] (http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html). – mattnewport

+0

Сколько разных 'T' вам нужно для вашего std :: vector ? Вы можете уйти с полиморфным контейнером, если сможете выяснить, что делать с помощью RTTI или с помощью какого-либо идентификатора, который вы реализуете самостоятельно. – VoidStar

+1

C++ статически типизирован, а типы значений карты должны быть одинаковыми на карте. Если вы сообщите нам о реальной проблеме, которую вы пытаетесь решить, мы сможем указать на C++ - идиоматический способ, или посмотрим на 'boost :: variant'. –

ответ

2

Так как вы знаете тип вы хотите, когда вы пишете код, я предлагаю этот подход (непроверенный):

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

Аргументами шаблона должно быть определено время компиляции. Если вы хотите, чтобы каждый ключ вашей карты соответствовал вектору другого типа, он не будет работать. Вы можете обойти его с помощью полиморфного контейнера, который возвращает void *, который вы нанесли на правильный тип, но я бы предложил попытаться найти другой способ сделать все, что вы хотите сделать с вашей картой.

+0

Полиморфный контейнер, вероятно, не должен содержать return 'void *', поскольку это не дает возможности выяснить, что такое тип. Лучше было бы требовать, чтобы сам контейнер был upcast (через switch on typeid или пользовательский идентификатор) в соответствующий подкласс, а затем возвращался реальный тип. – VoidStar

+0

Если он возвращает пустоту *, он предполагает, что вызывающий абонент знает, какой тип он возвращает. Очень опасно. Я предполагаю, что повышение может быть намного безопаснее. – fuzzything44

+0

is "ListOfInts" относится только к вектору ? – ggrr

0

Может быть, это может работать для вас:

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

С C++ 11, вы можете использовать using, он делает именно то, что вы хотите:

#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

Спасибо за предложение, но это не совсем то, что я пытаюсь сделать. Я не хочу создавать более одного экземпляра карты, но внутри нее хранятся несколько векторов любого типа. –

+0

Без проблем ;-) После прочтения вашего вопроса снова, я думаю, что должен был найти это сам. Наверное, я был в замешательстве, потому что это не типичный C++ способ сделать это. – alain

0

Как сказал малтенпорт, boost::variant - один из вариантов.

Или для поддержки любых типов используйте boost::any, используя явное использование any_cast.

Учитывая, что усиление может быть тяжелым весом, возможно, вы можете изобрести колесо и упростить его, чтобы он больше не увеличивался? лол