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

时间:2009-02-20 10:40:21

标签: c++ templates methods stdmap

我正在尝试声明RowColumn类,Row有一个私有std::map,其中的值指向模板Column 。像这样:

template <typename T>
class DataType {
  private:
    T type;
};
template <typename T>
class Field {
  private:
    T value;
    DataType<T> value;
};
class Row {
  private:
    std::map<unsigned long,Field*> column;
}; 

好吧,我原则上假设Row类不应该知道我们想要使用哪种Field(或Column},即它是否是{第1列中的{1}}或第2列中的Field<int>但我不确定Field<double>声明的正确语法是什么,或者Row::column在这个意义上是否有限我应该使用别的东西。

我向你提出建议,并提前感谢你们。

3 个答案:

答案 0 :(得分:24)

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>都不知道,只能通过保留某种类型的标志来检测由模板化派生类设置的基础 - 或者通过使用

询问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为您完成所有工作。您可以使用访问来使用正确的重载来调用仿函数。看一下manual

答案 1 :(得分:1)

  1. 你在那里遇到错误:你必须在Field中“重视”成员(一个应该是“类型”)。
  2. 请不要在地图的值中保留原始指针。使用boost::shared_ptr
  3. 此外,您应该有充分的理由来编写这样的类,其中有大量的DB /表处理代码,您可以使用它们。因此,如果它适用,请考虑使用现有的东西而不是编写自己的表处理代码。
  4. 现在,要回答你的问题:),字段&lt;&gt;类可以从所有数据类型共享的公共基类继承。这样,诸如列映射之类的容器可以将指针(使共享指针)保持为实例化模板类的派生对象。

答案 2 :(得分:0)

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开创了很多智慧(见Modern C++ Design, by Andrei Alexandrescu),但Boost更现代化,更受支持。

通常,您不会遍历字段 - 每个字段都有自己的类型。但是,你确实需要一个FieldBase。如果您需要这样的界面,那么在内部将字段存储为boost::array<FieldBase, N>(即Row<int,float,int>具有boost::array<FieldBase, 3>)可能也是值得的。但是,您永远不需要dynamic_cast FieldBase*。这是一个运行时测试,在编译时你总是知道每个T的确切Field<T>