我有这样的事情:
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
的存在,我认为它可以解决函数的问题,但对于变量则不然。
如果有人有解决方案或其他方法可以绕过这个,请告诉我。
答案 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而不需要派生类。如果这不是您所需要的,请提供更广泛的背景,以便更好地了解情况。
编辑:我已经更改了代码以包含一个没有额外功能的通用派生类。