如何以不同的数据类型作为值实现地图



我想将两种(不更多)不同的数据类型作为值放入地图中,如下所示:

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() {};

然后,我将您的typeXtypeY数据类型转换为从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();

注意:

  • 如果您使用typeXtypeY的动态创建实例,则应该更喜欢将智能指针存储在地图中,例如std::unique_ptrstd::shared_ptr,以简化内存管理。

  • 如果您必须坚持使用全局func()功能,则可以从相应的成员函数调用它们。我只会将参数变成指针或参考,以避免复制对象。

IDEONE上的完整代码

这可能是极端的过度杀伤,但是QT具有一个称为QVariant的变量,可用于映射到不同类型的(qt)变量。

文档此处:http://qt-project.org/doc/qt-5.0/qtcore/qvariant.html

您需要类型的擦除。

类型擦除是一种隐藏基础类型的模式,此类已知示例是Boost :: any,但请记住,增强任何人具有动态多态性行为(运行时动态调度)。另一方面,Boost ::变体是另一个示例,并使用模板元编程技术。请参阅变体与任何

最简单的解决方案可能是用基础类型的枚举编写自己的类型擦除。

最新更新