如何创建一个异构的boost::map?

32
我希望拥有一个具有同质键类型但异质数据类型的映射。
我想要能够执行以下类似的操作(伪代码):
boost::map<std::string, magic_goes_here> m;
m.add<int>("a", 2);
m.add<std::string>("b", "black sheep");

int i = m.get<int>("a");
int j = m.get<int>("b"); // error!

我可以将数据类型定义为基类的指针,但我不想这样做。

我以前从未使用过boost,但看过fusion库,不过还是搞不清楚需要做什么。

谢谢你的帮助。


如果您知道可能要放入映射中的所有可能类型,那么boost::variant将非常适合。如果您想要任何类型,则boost::any是正确的选择。 - Kurt
6个回答

40
#include <map>
#include <string>
#include <iostream>
#include <boost/any.hpp>

int main()
{
    try
    {
        std::map<std::string, boost::any> m;
        m["a"]  = 2;
        m["b"]  = static_cast<char const *>("black sheep");

        int i = boost::any_cast<int>(m["a"]);
        std::cout << "I(" << i << ")\n";

        int j = boost::any_cast<int>(m["b"]); // throws exception
        std::cout << "J(" << j << ")\n";
    }
    catch(...)
    {
        std::cout << "Exception\n";
    }

}

1
你可以使用std::decay代替繁琐的强制类型转换。 - Kerrek SB
这里初始化时不是只使用std::map而不是boost map吗?(链接:http://www.boost.org/doc/libs/1_35_0/libs/fusion/doc/html/fusion/container/map.html) - Tab

10

如何构建一个包含不同类型对象的<收藏容器>?

你不能直接构建,但可以通过添加额外的间接层来实现类似效果。在C/C++中,所有数组都是同构的(即元素都是相同类型)。但是,通过增加一个额外的间接层,可以使容器看起来是异构的(异构容器是指其包含的对象是不同类型的容器)。

有两种情况需要处理异构容器。

第一种情况是当想要保存在容器中的所有对象都公开派生自共同的基类时,[...]。

第二种情况是当对象类型是不相交的——它们不共享一个共同的基类时。此时的方法是使用一个句柄类。容器是一个句柄对象的容器(按值或按指针,任选;按值更容易)。每个句柄对象知道如何“持住”(即维护一个指向)想要放入容器中的对象之一。您可以使用单个句柄类,并使用几种不同类型的指针作为实例数据,或者使用阴影各种您希望包含的类型的句柄类的层次结构(需要容器为句柄基类指针)。这种方法的缺点是,每次更改可以包含的类型集合时,都会打开句柄类的维护。好处是您可以使用句柄类来封装大部分的内存管理和对象生命周期的不良效果。因此,即使在第一种情况下,使用句柄对象也可能是有益的。


8

7
谢谢David,这正是我所需要的。这是可行的解决方案。
#include <iostream>
using std::cout;
using std::endl;

#include <map>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::map<std::string, boost::any> t_map;


int main(int argc, char **argv)
{

  t_map map;
  char *pc = "boo yeah!";

  map["a"] = 2.1;
  map["b"] = pc;

  cout << "map contents" << endl;
  cout << any_cast<double>(map["a"]) << endl;
  cout << any_cast<char*>(map["b"]) << endl;

  return 0;
}

1
这应该是 const char *pc = "boo yeah!"; - Piotr Dobrogost

5
如果您想要支持一组有限的类型,Boost.Variant应该可以解决问题。

0

Boost肯定可以工作,但我认为使用Int作为融合映射的关键类型是更好的解决方案。没有类型擦除,可能更快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接