繁体   English   中英

C ++ std ::模板类值的映射

[英]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为您完成所有工作。 您可以使用访问来使用正确的重载来调用仿函数。 看看它的手册

  1. 你在那里得到一个错误:你必须在Field中“重视”成员(一个应该是“类型”)。
  2. 请不要在地图的值中保留原始指针。 使用boost :: shared_ptr
  3. 此外,您应该有充分的理由编写这样的类,其中有大量的DB /表处理代码,您可以使用它们。 因此,如果它适用,请考虑使用现有的东西,而不是编写自己的表处理代码。

现在,为了回答你的问题:),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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM