我正在尝试创建一个基类,它是std :: array的包装器,它重载了一堆常见的算术运算符。最终结果有点像std :: valarray,但是有静态大小。我这样做是因为我为我的库创建了一大堆子类,最终复制了这个功能。例如,我需要创建一个MyPixel类和一个MyPoint类,这两个类基本上只是静态大小的数组,我可以执行算术运算。
我的解决方案是创建一个StaticValArray基类,MyPoint和MyPixel可以从中派生。但是,为了禁止用户将MyPoint添加到MyPixel,我正在使用CRTP模式:
template<class T1, class T2>
struct promote
{
typedef T1 type; // Assume there is a useful type promotion mechanism here
};
template<class T, size_t S, template<typename... A> class ChildClass>
class StaticValArray : public std::array<T,S>
{
public:
// Assume there are some conversion, etc. constructors here...
template<class U>
StaticValArray<typename promote<T,U>::type,S,ChildClass> operator+
(StaticValArray<U,S,ChildClass> const & rhs)
{
StaticValArray<typename promote<T,U>::type,S,ChildClass> ret = *this;
std::transform(this->begin(), this->end(),
rhs.begin(), ret.begin(), std::plus<typename promote<T,U>::type>());
return ret;
}
// More operators....
};
这很酷,因为ChildClass可以有任意类模板参数,这个东西可以工作。例如:
template<class T, class U>
class MyClassTwoTypes : public StaticValArray<T,3,MyClassTwoTypes>
{ };
template<class T, class U>
class MyClassTwoTypes2 : public StaticValArray<T,3,MyClassTwoTypes2>
{ };
int main()
{
MyClassTwoTypes<int, float> p;
MyClassTwoTypes<double, char> q;
auto z = p + q;
MyClassTwoTypes2<double, char> r;
// r += q; // <-- Great! This correctly won't compile
return 0;
}
我的问题是:我想将一些ChildClass填充到StaticValArray的CRTP位中,该位不一定只有类作为其模板参数。例如,考虑这个N维点类:
template<class T, size_t S>
class MyPointND : public StaticValArray<T,S,MyPointND>
{ };
遗憾的是,这不会编译,因为size_t不是typename - 我得到了编译错误:
type/value mismatch at argument 3 in template parameter list for ‘template<class T, long unsigned int S, template<class ... A> class ChildClass> class StaticValArray’
test.C:36:54: error: expected a template of type ‘template<class ... A> class ChildClass’, got ‘template<class T, long unsigned int S> class MyPointND’
有没有办法创建一个可变绝对任何东西的变量模板模板参数包(typenames,int,size_t,double,等等?)因为最后我真的不在乎那里的类型是什么。请注意,我不能完全指定ChildClass(例如class MyPointND: public StaticValArray<T,S,MyPointND<T,S>>
),因为这会破坏我的类型提升机制。
答案 0 :(得分:3)
如果使用std :: integral_constant代替size_t,该怎么办?您可以在其中嵌入数组大小的数值,并且可以将其用作类型。
修改强>
为了减少冗长,你可以定义自己的整数常量类,如:
template <std::size_t N>
struct size_ : std::integral_constant<std::size_t,N> {};
然后你可以像这样使用它:
MyPointND<int,size_<3>> x;
答案 1 :(得分:0)
您需要做的是拥有一个traits
类,专门针对每种类型包含类型提升所需的内容,然后将完整类型传递给StaticValArray。
此外,对于decltype
,你不应该需要这样的东西 - decltype
会通过添加一个浮点数和一个int来告诉你你得到了什么。
template<class U>
StaticValArray<decltype(*(T*)nullptr + *(U*)nullptr),S,ChildClass> operator+
(StaticValArray<U,S,ChildClass> const & rhs)
{
StaticValArray<decltype(*(T*)nullptr + *(U*)nullptr),S,ChildClass> ret = *this;
std::transform(this->begin(), this->end(),
rhs.begin(), ret.begin(), std::plus<decltype(*(T*)nullptr + *(U*)nullptr)>());
return ret;
}