2014-02-16 1 views
0

Возьмем следующий «типа» словарь - его ключи должны быть типы и значения экземпляра этого типа:словарь с ключами компиляции времени, или типов в качестве ключей

class TypeDictionary { 
public: 
    template<class T> void insert(T t); 
    template<class T> T& get(); 
    // implementation be here -- and the question is about this 
}; 

struct Foo; 
struct Bar; 

void userOfTypeDictionary() { 

    TypeDictionary td; 

    td.insert(Foo()); 
    td.insert(Bar()); 
    td.insert(double(3.14)); 
    // and other unknown (to TypeDictionary) 
    // list of types attached 


    // later on, in a different scope perhaps 
    Foo& f = td.get<Foo>() ; 
    Bar& f = td.get<Bar>(); 
    double pi = tg.get<double>(); 
    // ... 
} 

Данный TypeDictionary имеет растущий набор типов «зарегистрирован», но, конечно, объект должен допускать произвольный набор типов и, возможно, другой набор для каждого экземпляра этого класса.

Что касается реалистичного мотивационного варианта использования, подумайте о менеджере плагинов. В любой момент времени к нему прикрепляется произвольный гетерогенный набор объектов, и задача менеджера заключается в том, чтобы управлять временем жизни присоединенных объектов и возвращать (ссылку) им при запросе безопасным типом образом ,

Любые идеи о том, возможно ли такое? Это прекрасно, если стратегия предполагает использование библиотеки, например Boost.Fusion или аналогичной.

ответ

2

Минимальный, но, вероятно, неоптимальный способ сделать это - использовать типовые версии std::get, которые доступны только на C++ 14. Таким образом, ваш словарь будет просто получить или обернуть кортеж:

template<typename... T> 
struct dict 
{ 
    std::tuple<T...> t; 

    template<typename E> 
    void insert(E e) { std::get<E>(t) = e; } 

    template<typename E> 
    E& get() { return std::get<E>(t); } 
}; 

struct Foo {}; 
struct Bar {}; 

using TypeDictionary = dict<Foo, Bar, double>; 

выше дает желаемое поведение с clang -std=c++1y, но не с g++ до 4.8.2, по крайней мере.

Во всяком случае, идея состоит в том, что у вас есть предопределенный список ключей типа, заданных спереди, и ваш словарь ведет себя как плоский набор фиксированного размера, что означает, что он включает в себя размер для его элементов (по крайней мере, непустых), даже если вы не вызываете insert(), и в этом случае эти элементы построены по умолчанию.

Я не обращал на это особого внимания, чтобы дать константы или неконстантные версии методов или переместить операции. Вышеизложенное - только идея. Конечно, это так просто, что вы можете просто использовать std::tuple и std::get().

Чтобы словарь с фиксированным типом, независимо от его типов элементов, был более сложным; это вопрос стирания типа, и в этом отношении он напоминает std::function. Для получения действительно динамического типа гетерогенного контейнера (без заливок, виртуальных функций и т. Д.) Невозможно с данным синтаксисом, я думаю. Возможно создание нового словаря нового (увеличенного) типа после каждой операции insert(), например.

auto new_d = d.insert(3.14); 

Это просто сцепить существующий tuple<T...> с новым элементом, чтобы дать новый tuple<T...,double>.

+0

благодарит за ваш ответ! Таким образом, по мере того, как вы создаете изображение, первая версия кортежа не адресует самую важную спецификацию, которая заключается в том, что список типов не предопределен (если бы это было так, Boost.Fusion можно было бы использовать просто прекрасно, в частности, boost :: фьюжн :: набор). Вторая половина вашего комментария более интересна, и, на самом деле, с каждой вставкой есть определенный базовый тип. Но было бы более интересно, если TypeDisctionary каким-то образом управляет им, с помощью какого-то стирания типа или иначе .. – Nick

+0

Вы можете использовать что-то вроде [boost :: any] (http://www.boost.org/doc/libs/1_55_0/ doc/html/any.html) для части стирания типа, хотя она содержит неприятный низкоуровневый код и использует бесплатный магазин, если я правильно помню (я создал аналогичную библиотеку, которая, по крайней мере, не использует бесплатный магазин) , Это позволяет использовать гетерогенные контейнеры, но сам по себе не решает проблему поиска данного ключа среди разных типов. – iavr