Введите карту в C ++ - PullRequest
       51

Введите карту в C ++

1 голос
/ 03 февраля 2011

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

Я пытаюсь создать класс, каждый экземпляр которого будет управлять тем, как данные связаны друг с другом в объекты.Класс должен предпочтительно содержать методы:

class DataManager {
  Object CreateObject();
  void DestoryObject();

  template<typename DataType>
  DataType* AddDataToObject(Object o)

  template<typename DataType>
  DataType* GetDataForObject(Object o)

  template<typename DataType>
  void RemoveDataFromObject(Object o)
};

Объект в приведенном выше коде - это просто некоторый идентификатор - int на данный момент и не содержит никаких данных или методов (это не должно изменяться).Используемый выше DataType может быть в основном любым классом, однако общая ситуация такова, что это просто структура без методов.Полный список вещей, которые можно использовать в качестве DataType, известен во время компиляции, но его не следует кодировать, так как он меняется довольно часто.

Две цели, которые я пытаюсь достичь, это: - ремонтопригодность / скорость - пользователь должениметь возможность добавлять новые структуры DataType без изменения этого кода - Скорость - должна быть максимально быстрой

Структура данных в таком случае будет выглядеть примерно так:

map< DataTypeType, map< Object, ContainerBase* > >

Итак, как этого добиться?Повысит ли это справку :: mpl :: map и как?

По сути, это должно быть возможным, поскольку все типы данных известны во время компиляции.

Ответы [ 4 ]

0 голосов
/ 15 ноября 2017

Вы можете создать кортеж с отображением между типами:

template < std::size_t sz, typename... Types >
struct TypeMap {
    TypeMap (std::array< std::tuple< Types... >, sz > m) : mapping (m) {
    }

    std::array< std::tuple< Types... >, sz > mapping;
};

Затем укажите функцию для преобразования

template < typename To, typename From, std::size_t sz, typename... T >
To convert (From from, TypeMap< sz, T... > m) {
    for (auto entry : m.mapping) {
        if (utils::get< From > (entry) == from) {
            return utils::get< To > (entry); //Tricky part here
        }
    }

    throw std::logic_error ("No entry in the typemap");
}

Затем укажите отображение

const auto map = TypeMap{{std::make_tuple (red, "red", 1), 
                          std::make_tuple (green, "green", 2),
                          std::make_tuple (blue, "blue", 3)}};

и, наконец, вы можете вызвать функцию преобразования и преобразовать любой тип в любой другой тип;)

См. Мою статью здесь: https://cpptelepathy.wordpress.com/

Вам понадобится этот файл https://github.com/alekstheod/tnnlib/blob/master/src/Utilities/MPL/Tuple.h

за утилиту :: получить

0 голосов
/ 04 февраля 2011

Если вы хотите эквивалент map от типов к значениям, и он может быть глобальным, вы можете использовать static членов:

template <typename T>
struct DataManager {
  static std::map<void*, Object> this_type_map;
};

плюс соответствующие определения DataManager<T>::this_type_map дляразличные значения T (но эти определения не обязательно должны находиться в одном исходном файле).После этого вы можете создавать объекты карты типов с помощью (void*)(new int), освобождать их с помощью delete (int*)(m) и искать объект для экземпляра m и типа T с использованием DataManager<T>::this_type_map[m].Конечно, вы захотите обернуть их в функции или объекты.Обратите внимание, что вы можете иметь тип, отличный от Object, в качестве типа значения в map, включая (с использованием специализаций шаблонов), имеющий различный тип значения для каждого типа ключа в карте типов.

0 голосов
/ 16 ноября 2014

Я думаю, что вам нужен std :: tuple c ++ 11 или игра с boost :: tuple для c ++ 03

template<typename T>
struct Entry{
  T t;
};

int main(int argc, char **argv) {
  std::tuple< int, float, double, Entry<int> > objects;
  std::get<0>(objects) = 3;
  std::get<3>(objects).t = 5;

  //
  utils::get< Entry<int> >(object).t = 5;
  return 0;
}

get by type можно реализовать как здесь:*

0 голосов
/ 03 февраля 2011
class DataManager {
    struct internal_base { virtual ~internal_base() {} };
    template<typename T> struct internal_data : public internal_base {
        T t;
    };
    boost::unordered_map<Object, boost::unordered_map<std::string, boost::unique_ptr<internal_base>>> data;
public:
    Object CreateObject() { return Object(); }
    void DestroyObject(Object o) { data.erase(o); }

    template<typename DataType> DataType* AddDataToObject(Object o, std::string name) {
        internal_data<T>* ptr = new internal_data<T>();
        data[o][name] = ptr;
        return &ptr->t;
    }

    template<typename DataType> DataType* GetDataForObject(Object o, std::string name) {
        internal_base* ptr = data[o][name].get();
        if (internal_data<DataType>* dptr = dynamic_cast<internal_data<DataType>*>(ptr)) {
            return &dptr->t;
        else
            return 0;
    }

    void RemoveDataFromObject(Object o, std::string name) {
        data[o][name] = 0;
    }
};

Этот код делает некоторые предположения, например, конструкцию по умолчанию для типа объекта, и что он является хэшируемым.Но это не должно быть слишком сложно изменить.Было бы намного сложнее получить определенное поведение, если вы хотите, чтобы только один элемент данных каждого типа был связан с конкретным объектом, потому что вы не можете полагаться на RTTI, чтобы возвращать уникальные имена для каждого возможного типа данных.

...