C++ map with different data types as values

2019-01-25 19:49发布

问题:

my problem is as follows: I want to put two (no more) different datatypes as values into a map.

typeX A, B, ...;
typeY Z, Y, ...;

void func (typeX) { ... }

void func (typeY) { ... }


std::map <std::string, what_to_put_here?? >map;
map["a"] = A;
map["z"] = Z;
...

std::vector<std::string> list;
//this list will be sth. like "a", "y", ...

for (unsigned int i = 0; i < list.size(); ++i)
    func( map[list[i]] )

Obviously this doesn't work as the map will only accept one data type of value. When looping over "list", the call to "func" should be unambiguous since the type of map[list[i]] is known.

I want to avoid explicit casting or typechecking, i.e. sth like

    if (typeid( map[list[i]] ).name() == "typeX")
        func( map[list[i]] )
    else if (typeid( map[list[i]] ).name() == "typeY")
        func( map[list[i]] )

Can you tell me if this is possible? Again, it will be limited to only two different data types. Thanks!

回答1:

You want to use boost::variant:

std::map <std::string, boost::variant<typeX, typeY>>


回答2:

Are typeX and typeY subclasses of a typeBase class ? If so, you could do a std::map<std::string,typeBase*> to store both typeX* and typeY* in the map.



回答3:

With some metaprogramming you can easily build an heterogenous map which can store any type from a given set of types. Here is an example which does this, without type erasure nor the need to visit the values.



回答4:

One way to implement a multi-type map is by using the nifty features of std::tuple in C++11, which allows access by a type key. You can wrap this to create access by arbitrary keys. An in-depth explanation of this (and quite an interesting read) is available here:

https://jguegant.github.io/blogs/tech/thread-safe-multi-type-map.html



回答5:

This would probably be extreme overkill, but QT has a variable called QVariant which can be used to map to different types of (QT) variables.

Documentation here: http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html



回答6:

You need a type erasure.

Type erasure is a pattern that hides the underlying type, such known examples are boost::any, but keep in mind that boost any has a dynamic polymorphic behavior (dynamic dispatch at runtime). boost::variant on the other hand is another example and uses template metaprogramming techniques. see variant vs any

The simplest solution though, could be writing your own class type erasure with an enum for the underlying type.



标签: c++ map