Вопрос

Я хочу иметь карту, которая имеет однородный тип ключа, но разнородные типы данных.

Я хочу иметь возможность делать что-то вроде (псевдокод):

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, но не могу понять, что мне нужно делать.

Спасибо за вашу помощь.

Это было полезно?

Решение

#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";
    }

}

Другие советы

Как создать < любимый контейнер > ; объектов разных типов?

  

Вы не можете, но вы можете подделать это довольно хорошо. В C / C ++ все массивы являются однородными (то есть все элементы одного типа). Однако с дополнительным уровнем косвенности вы можете создать вид гетерогенного контейнера (гетерогенный контейнер - это контейнер, в котором содержатся объекты разных типов).

     

Есть два случая с гетерогенными контейнерами.

     

Первый случай возникает, когда все объекты, которые вы хотите сохранить в контейнере, являются общедоступными из общего базового класса. [...]

     

Второй случай возникает, когда типы объектов не пересекаются & # 8212; у них нет общего базового класса.
  Подход здесь заключается в использовании класса дескриптора. Контейнер - это контейнер объектов-дескрипторов (по значению или по указателю, по вашему выбору; по значению проще). Каждый объект-дескриптор знает, как & Сохранить & Quot; (т.е. поддерживать указатель на) один из объектов, которые вы хотите поместить в контейнер. Вы можете использовать либо один класс дескриптора с несколькими различными типами указателей в качестве данных экземпляра, либо иерархию классов дескрипторов, которые скрывают различные типы, которые вы хотите содержать (требуется, чтобы контейнер имел указатели базового класса дескрипторов). Недостатком этого подхода является то, что он открывает классы дескрипторов для обслуживания каждый раз, когда вы изменяете набор типов, которые могут содержаться. Преимущество заключается в том, что вы можете использовать классы дескрипторов для инкапсуляции большей части уродства управления памятью и времени жизни объекта. Таким образом, использование объектов дескриптора может быть полезным даже в первом случае.

будет повысить :: любой сделать трюк для вас?

Спасибо, Дэвид, это было то, что мне было нужно. Вот рабочее решение.

#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;
}

Если вы хотите поддерживать ограниченный набор типов, Boost.Variant должен помочь.

Конечно,

boost любой работает, но я думаю, что использование Int для ввода Technology в качестве ключевого типа карты слияния является лучшим решением. Нет стирания типа и, возможно, быстрее

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top