带有编译时密钥或类型为密钥的字典

时间:2014-02-16 20:27:31

标签: c++ boost-fusion

使用以下“类型”字典 - 它的键应该是类型,并且值为该类型的实例:

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或类似的,那么这很好。

1 个答案:

答案 0 :(得分:2)

这样做的最小但可能是次优的方法是使用仅在C ++ 14中可用的std::get的类型版本。这样你的字典就可以简单地派生或包装一个元组:

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(),在这种情况下这些元素是默认构造的。

这里我没有特别注意给出const /非const版本的方法,或者移动操作。以上只是为了得到这个想法。当然,这很简单,您可以直接使用std::tuplestd::get()

要使字典具有固定类型而不管其元素类型是否相当困难;这是类型擦除的问题,在这方面它类似于std::function。我认为使用给定的语法无法获得真正动态的类型安全的异构容器(没有强制转换,虚函数等)。可能的是在每次insert()操作后获得新的(放大的)类型的新字典,例如

auto new_d = d.insert(3.14);

这只会将现有的tuple<T...>与新元素连接起来,以提供新的tuple<T...,double>