我想将两种(不更多)不同的数据类型作为值放入地图中,如下所示:
: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 something like "a", "y", ...
for (unsigned int i = 0; i < list.size(); ++i)
func( map[list[i]] )
显然这不起作用,因为地图只能接受一种值的值。但是,当通过list
循环时,func()
的调用应该是明确的,因为map[list[i]]
的类型已知。
我想避免明确的铸造或输入检查,即类似的东西:
if (typeid( map[list[i]] ).name() == "typeX")
func( map[list[i]] )
else if (typeid( map[list[i]] ).name() == "typeY")
func( map[list[i]] )
这可能吗?同样,它将仅限于两种不同的数据类型。
您要使用boost::variant
:
std::map <std::string, boost::variant<typeX, typeY>>
是TypeBase类的类型和类型子类吗?如果是这样,您可以执行std::map<std::string,typeBase*>
在地图中存储Typex*和Typey*。
使用一些元编程,您可以轻松构建一个异质映射,该映射可以从给定的一组类型中存储任何类型。这是一个执行此操作的示例,没有类型的擦除也不需要访问值。
实现多类映射的一种方法是使用C 11中的std :: tuple的漂亮功能,该功能允许通过类型键访问。您可以将其包装以通过任意键创建访问权限。此处可用的深入说明(这是一个有趣的读物):
https://jguegant.github.io/blogs/tech/thread-safe-multi-type-map.html
如果您不想使用Boost,那么我认为构建ROM1504提出的类层次结构是有道理的。我将用func()
作为成员函数实现抽象基类:
class Base {
public:
virtual void func() = 0;
};
void Base::func() {};
然后,我将您的typeX
和typeY
数据类型转换为从Base
派生的子类别,如下所示:
class typeX : public Base {
public:
void func() { std::cout << "typeX::func()" << std::endl; };
int i; // Example for your original 'typeX' content.
};
class typeY : public Base {
public:
void func() { std::cout << "typeY::func()" << std::endl; };
std::string s; // Example for your original 'typeY' content.
};
在这里,func()
实现将采用您相应的全局func()
功能的内容。接下来,您的地图需要将指针存储至Base
作为值:
std::map<std::string, Base*> map;
map["a"] = &A;
map["z"] = &Z;
因此,您可以按以下方式实现循环(使用基于C 11范围的for
循环):
for (auto const &list_item : list)
map[list_item]->func();
注意:
如果您使用
typeX
和typeY
的动态创建实例,则应该更喜欢将智能指针存储在地图中,例如std::unique_ptr
或std::shared_ptr
,以简化内存管理。如果您必须坚持使用全局
func()
功能,则可以从相应的成员函数调用它们。我只会将参数变成指针或参考,以避免复制对象。
IDEONE上的完整代码
这可能是极端的过度杀伤,但是QT具有一个称为QVariant的变量,可用于映射到不同类型的(qt)变量。
文档此处:http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html
您需要类型的擦除。
类型擦除是一种隐藏基础类型的模式,此类已知示例是Boost :: any,但请记住,增强任何人具有动态多态性行为(运行时动态调度)。另一方面,Boost ::变体是另一个示例,并使用模板元编程技术。请参阅变体与任何
最简单的解决方案可能是用基础类型的枚举编写自己的类型擦除。