[英]C++ std::map of template-class values
我正在尝试声明一个Row
和一个Column
类, Row
有一个私有的std::map
,其值指向一个模板化的Column
。 像这样的东西:
template <typename T> class DataType {
private:
T type;
};
template <typename T> class Field {
private:
T value;
DataType<T> type;
};
class Row {
private:
std::map<unsigned long,Field*> column;
};
好吧,我原则上假设Row
类不应该知道我们想要使用哪种Field
(或Column
),即它是第1列中的Field<int>
还是第2列中的Field<double>
但是我不确定Row::column
声明的正确语法是什么,或者std::map
在这个意义std::map
是否有限,我应该使用其他东西。
我建议你提出建议,并提前感谢你们。
单独的Field
不是类型,而是可以生成类型族的模板,例如Field<int>
和Field<double>
。 所有这些字段都不相关,使得一个字段以某种方式从另一个或那样派生。 所以你必须在所有这些生成的类型之间建立一些关系。 一种方法是使用通用的非模板基类:
class FieldBase { };
template <typename T>
class Field : public FieldBase {
private:
T value;
DataType<T> type;
};
class Row {
private:
std::map<unsigned long,FieldBase*> column;
};
并考虑在代码中使用智能指针而不是原始指针。 无论如何,现在问题是类型信息丢失 - 无论你指向Field<double>
还是Field<int>
都不知道,只能通过在base中保留某种type-flag来检测这是由模板化的派生类设置的 - 或者通过询问RTTI使用
dynamic_cast<Field<int>*>(field) != 0
但那很难看。 特别是因为你想要的是一个价值语义。 也就是说,你希望能够复制你的行,它会复制其中的所有字段。 并且你想要在存储双精度时得到一个双精度 - 而不是先使用RTTI来破解你的派生类型。
一种方法是使用有区别的联合。 这基本上是一些任意类型的联合,另外还有一个type-flag,它存储当前存储在该字段中的值(例如,是否为double,int,...)。 例如:
template <typename T>
class Field {
private:
T value;
DataType<T> type;
};
class Row {
private:
std::map<unsigned long,
boost::variant< Field<int>, Field<double> > >
column;
};
boost :: variant为您完成所有工作。 您可以使用访问来使用正确的重载来调用仿函数。 看看它的手册
现在,为了回答你的问题:),Field <>类可以继承自所有数据类型共享的公共基类。 这样,诸如列映射之类的容器可以将指针(使该共享指针)保持为实例化模板类的派生对象。
Row< int, float, int>
与Row<int, std::string>
。 显然, Row<int,float,int>.field<0>
应该是Field<int>
而Row<int,float,int>.field<1>
应该是Field<float>
。 并且Row<int,float,int>.field<3>
是编译器错误。
最简单的方法是使用Boost。 很多情报都是由Loki开创的(参见现代C ++设计 ,作者:Andrei Alexandrescu ),但Boost更现代,更受支持。
通常,您不会遍历字段 - 每个字段都有自己的类型。 但是,你确实需要一个FieldBase
。 如果你需要这样的接口,也可能值得在内部存储字段作为boost::array<FieldBase, N>
(即Row<int,float,int>
有一个boost::array<FieldBase, 3>
)。 但是,您永远不需要dynamic_cast
那个FieldBase*
。 这是一个运行时测试,你总是在编译时知道每个Field<T>
的确切T
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.