Шаблон Variadic - PullRequest
       1

Шаблон Variadic

2 голосов
/ 15 апреля 2011

Я пытаюсь создать базовый класс, который является оберткой вокруг 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 в бит CRTP StaticValArray, который не обязательно имеет только классы в качестве параметров шаблона. Например, рассмотрим этот класс 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’

Есть ли какой-либо способ создать пакет параметров шаблона шаблона с переменным числом элементов, который может быть абсолютно любым (typenames, ints, size_t's, doubles, что угодно?), Потому что в конце концов мне действительно все равно, какой тип там. Обратите внимание, что я не могу просто полностью указать ChildClass (например, class MyPointND: public StaticValArray<T,S,MyPointND<T,S>>), потому что это нарушит мой механизм продвижения типов.

Ответы [ 2 ]

3 голосов
/ 15 апреля 2011

Что если вместо size_t вы использовали std :: integra_constant?Вы бы вставили в него числовое значение размера вашего массива и могли бы использовать его как тип.

РЕДАКТИРОВАТЬ

Чтобы уменьшить многословие,Вы можете определить свой собственный класс целочисленных констант, например:

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

Тогда вы можете использовать его следующим образом:

MyPointND<int,size_<3>> x;
0 голосов
/ 15 апреля 2011

Вам нужно иметь класс 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...