基本上我希望 MyClass 包含一个将字段名称(字符串)映射到任何类型的值的 Hashmap。为此,我编写了一个单独的 MyField 类来保存类型和值信息。
这是我到目前为止所拥有的:
template <typename T>
class MyField {
T m_Value;
int m_Size;
}
struct MyClass {
std::map<string, MyField> fields; //ERROR!!!
}
但正如你所见,map 声明失败,因为我没有为 MyField 提供类型参数…
所以我想它必须是这样的
std::map< string, MyField<int> > fields;
或者
std::map< string, MyField<double> > fields;
但这显然破坏了我的整个目的,因为声明的地图只能包含特定类型的 MyField 。我想要一个可以包含任何类型的 MyField 类的地图。
有什么办法可以做到这一点..?
原文由 user3794186 发布,翻译遵循 CC BY-SA 4.0 许可协议
Blindy 的答案非常好(+1),但只是为了完成答案:还有另一种方法可以在没有库的情况下使用动态继承:
优点:
缺点:
因此,如果可以,请使用 boost::any 或 boost::variant 作为默认值,否则仅考虑此选项。
要解决最后一个缺点,您可以使用智能指针:
然而,还有一个潜在的更成问题的地方:
它强制您使用 new/delete(或 make_unique/shared)创建对象。这意味着实际对象是在分配器提供的任何位置(大多数是默认位置)的空闲存储(堆)中创建的。因此,由于 缓存未命中,经常浏览对象列表并没有可能那么快。
如果您关心尽可能快地循环遍历此列表的性能(如果不是,请忽略以下内容),那么您最好使用 boost::variant (如果您已经知道您将使用的所有具体类型)或使用某种类型擦除的多态容器。
这个想法是容器将管理相同类型的对象数组,但仍然公开相同的接口。该接口可以是一个概念(使用鸭子类型技术)或动态接口(如我的第一个示例中的基类)。优点是容器会将相同类型的对象保存在单独的向量中,因此通过它们很快。只有从一种类型转换到另一种类型不是。
这是一个例子(图片来自那里): http ://bannalia.blogspot.fr/2014/05/fast-polymorphic-collections.html
但是,如果您需要保持插入对象的顺序,这种技术就会失去兴趣。
无论如何,有几种可能的解决方案,这在很大程度上取决于您的需求。如果您对自己的案例没有足够的经验,我建议使用我在示例中首先解释的简单解决方案或 boost::any/variant。
作为对这个答案的补充,我想指出非常好的博客文章,这些文章总结了您可以使用的所有 C++ 类型擦除技术,并附有评论和优缺点: