【发布时间】:2011-04-15 01:21:02
【问题描述】:
我正在尝试创建一个基类,它是 std::array 的包装器,它重载了一堆常见的算术运算符。最终结果将有点像 std::valarray,但具有静态大小。我这样做是因为我正在为我的库创建大量子类,这些子类最终会复制此功能。例如,我需要创建一个 MyPixel 类和一个 MyPoint 类,它们本质上都是静态大小的数组,我可以对其进行算术运算。
我的解决方案是创建一个可以派生 MyPoint 和 MyPixel 的 StaticValArray 基类。但是,为了禁止用户将 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 不是类型名 - 我得到编译器错误:
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’
有没有办法创建一个可变参数模板模板参数包,它可以是任何东西(类型名、整数、size_t、双精度数等等?),因为最后我真的不在乎里面的类型是什么。请注意,我不能只完全指定 ChildClass(例如 class MyPointND: public StaticValArray<T,S,MyPointND<T,S>>),因为这会破坏我的类型提升机制。
【问题讨论】:
-
关于
promote结构,你可以在结构中利用decltype:typedef decltype(T+U) type;。 -
我真正的推广实现确实使用了这个,为了清楚起见,我只是称之为“推广”。为简洁起见,此处省略了详细信息。