开发者

Variadic Template Template

I am trying to create a base class that is a wrapper around std::array that overloads a bunch of common arithmetic operators. The end result will be sort of like std::valarray, but with static size. I'm doing this because I am creating a whole host of child classes for my library that end up replicating this functionality. For example, I need to create a MyPixel class and a MyPoint class, both of which are essentially just statically sized arrays that I can perform arithmetic on.

My solution is to create a StaticValArray base class from whic开发者_运维百科h MyPoint and MyPixel can derive. However to disallow users from adding a MyPoint to a MyPixel, I'm using the CRTP pattern as such:

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....
};

This is pretty cool, because the ChildClass can have any arbitrary class template parameters, and this thing will work. For example:

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;
}

My problem is this: I would like to stuff some ChildClass into the CRTP bit of StaticValArray that doesn't necessarily have just classes as its template parameters. For example, consider this N-Dimensional Point class:

template<class T, size_t S>
class MyPointND : public StaticValArray<T,S,MyPointND>
{ };

This unfortunately won't compile, because size_t is not a typename - I get the compiler error:

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’

Is there any way to create a variadic template template parameter pack that can be absolutely anything (typenames, ints, size_t's, doubles, whatever?) because in the end I really don't care what the type is in there. Note that I can't just fully specify ChildClass (e.g. class MyPointND: public StaticValArray<T,S,MyPointND<T,S>>) because this would break my type promotion mechanism.


What if, in place of the size_t, you used an std::integral_constant? You would embed the numerical value of the size of your array in it, and you could use it as a type.

EDIT

In order to reduce the verbosity, you could define your own integral constant class, something like:

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

Then you could use it like this:

MyPointND<int,size_<3>> x;


What you need to do is have a traits class, specialized for each type containing whatever you need for type promotion, and then pass in the complete type to the StaticValArray.

Moreover, with decltype, you shouldn't need anything like this- decltype will tell you what you get by adding a float and an 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;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜