可变模板模板

我正在尝试创建一个基类,它是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不是一个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,ints,size_t's,double,等等),因为最后我真的不在乎类型在那里。 请注意,我不能完全指定ChildClass(例如, class MyPointND: public StaticValArray<T,S,MyPointND<T,S>> ),因为这会破坏我的类型提升机制。


如果代替size_t使用std :: integral_constant? 您可以将数组大小的数值嵌入其中,并且可以将其用作类型。

编辑

为了减少冗长,你可以定义你自己的整型常量类,例如:

template <std::size_t N>
struct size_ : std::integral_constant<std::size_t,N> {};

然后你可以像这样使用它:

MyPointND<int,size_<3>> x;

你需要做的是有一个traits类,专门为每种类型提供类型提升所需的类型,然后将完整类型传递给StaticValArray。

而且,使用decltype ,你不需要像这样的任何东西 - decltype会通过添加一个float和一个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;
}
链接地址: http://www.djcxy.com/p/62155.html

上一篇: Variadic Template Template

下一篇: Guide to understanding gitk?