Подтвердить что ты не робот

Как вы делаете гетерогенную boost:: map?

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

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

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

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

4b9b3361

Ответ 1

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

}

Ответ 2

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

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

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

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

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

Ответ 3

Может ли boost:: any сделать трюк для вас?

Ответ 4

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

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

Ответ 5

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

Ответ 6

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