C ++ - 基于模板参数将变量和函数添加到模板化类中

时间:2016-07-06 21:56:01

标签: c++ templates inheritance specialization

我有这样的事情:

  val typeArgs = typeParams.map(_.name)
  val applyDef = q"""${name.toTermName}.apply[..$typeArgs]"""
  c.warning(c.enclosingPosition, showRaw(applyDef))

  q"""
    object ${name.toTermName} {
      def defaultApply[..$typeParams]:
          (..${valueParams.map(_.tpt)}) => $name[..$typeArgs] = $applyDef
    }
  """

如果template <typename T, int N> class Data { typedef Data<T, N> data; public: T y; data *ptr[N]; }; ,我希望能够在类中添加变量和函数,例如:

N == 2

我知道可以使用继承或专门化,但两者都存在问题。

继承在这种特定情况下没有任何意义,因为变量template <typename T, int N> class Data { typedef Data<T, N> data; public: T y; data *ptr[N]; /* if N == 2, add the following members to the class */ int x; data *left() { return ptr[0] }; data *right() { return ptr[1] }; }; 指向同一个类,所以如果我使用:

ptr

template <typename T> class Data2 : Data<T, 2> { typedef Data2<T> data; public: int x; data *left() { return ptr[0] }; // Error (ptr has type Data<T,N>) data *right() { return ptr[1] }; // Error }; ptr继承的变量Data2将指向类Data而不是Data,从而使基类无效。

专业化的问题是我必须将整个基类复制到专门化,对于较小的情况,这可能没问题,但是如果我有一个非常复杂的类,或者我想要多个值的自定义变量和函数Data2,这是不切实际的。

我也知道N的存在,我认为它可以解决函数的问题,但对于变量则不然。

如果有人有解决方案或其他方法可以绕过这个,请告诉我。

3 个答案:

答案 0 :(得分:4)

您可以为N的特定值专门化模板声明,并为基类中的公共代码使用另一级别的继承间接,这不依赖于N

template <typename T> class DataBase {
    public:
        T y;
};

template <typename T, int N> class Data : public DataBase {
    typedef Data<T, N> data;
    public:
        data *ptr[N];
};

另外,如果不知道你到底想要什么,我会说像

typedef T DataType;
typedef T* DataTypePtr;
基类中的

对我来说更有意义。

答案 1 :(得分:2)

  

在这种特定情况下,继承没有任何意义

这取决于它是单独使用还是与friend类声明和 CRTP 惯用法混合使用:

template<typename, int>
struct BaseData { };

template<typename T>
struct BaseData<T, 2> {
    int x;
    typename T::data *left() { return static_cast<T*>(this)->ptr[0]; }
    typename T::data *right() { return static_cast<T*>(this)->ptr[1]; }
};

template <typename T, int N>
class Data: public BaseData<Data, N> {
    friend class BaseData<Data, N>;
    using data = Data<T, N>;

public:
   T y;
    data *ptr[N];
};

答案 2 :(得分:0)

正如skypjack所提到的,可以使用CRTP。 A&#34;工作&#34;接近你的例子的例子如下所示:

template <typename T, int N, typename Derived >
class DataBase {
    public:
        typedef Derived data;
        T y;
        typename DataBase<T,N,Derived>::data *ptr[N];
};


template <typename T, int N>
class Data : public DataBase< T, N, Data<T,N> > {
};


template <typename T>
class Data2 : public DataBase< T, 2, Data2<T> > {
    public:
        int x;
        typename DataBase<T,2,Data2<T> >::data* left()  { return DataBase<T,2,Data2<T> >::ptr[0]; }
        typename DataBase<T,2,Data2<T> >::data* right() { return DataBase<T,2,Data2<T> >::ptr[1]; }
};

int main() {


  Data2<double> myData;

  Data<double,5> myData5;

  myData.y = 3.0;
  myData.x = 5;

  myData.left();
  myData.right();

  myData5.y = 42.0;

}

CRTP当然意味着你永远不能直接实例化类DataBase而不需要派生类。如果这不是您所需要的,请提供更广泛的背景,以便更好地了解情况。

编辑:我已经更改了代码以包含一个没有额外功能的通用派生类。