使用以下“类型”字典 - 它的键应该是类型,并且值为该类型的实例:
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或类似的,那么这很好。
答案 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::tuple
和std::get()
。
要使字典具有固定类型而不管其元素类型是否相当困难;这是类型擦除的问题,在这方面它类似于std::function
。我认为使用给定的语法无法获得真正动态的类型安全的异构容器(没有强制转换,虚函数等)。可能的是在每次insert()
操作后获得新的(放大的)类型的新字典,例如
auto new_d = d.insert(3.14);
这只会将现有的tuple<T...>
与新元素连接起来,以提供新的tuple<T...,double>
。