статический список инициализаторов для класса-оболочки - PullRequest
2 голосов
/ 20 августа 2011

Можно ли как-то "передать" статический список инициализаторов во время конструирования классу-оболочке контейнера, который, в свою очередь, инициализирует его член?

struct bar {
  bar(void * ptr): ptr(ptr) {}
  void * ptr;
};

template<class T, int N>
struct foo
{
  foo( args ) :store(args)  {}  // here the arg list should be passed

  T store[N];
};

int main()
{
  bar b[2]={NULL,NULL};
  foo<bar,2> f(NULL,NULL); // This should be possible
}

К сожалению, я не могу использовать STL или Boost.

Позвольте мне объяснить, если вы сомневаетесь в полезности этого.Во-первых, это очень «готовая» установка.Объяснение всей установки не подходит для публикации здесь, и это не поможет.Просто представьте себе случай, когда у вас есть вложенное дерево шаблонов выражений, вы просматриваете его во время компиляции, собираете вовлеченные объекты и сохраняете их в оболочку контейнера, как описано выше.Если у вас есть дополнительные вопросы, пожалуйста, спросите.

Отредактировано: конструктор T по умолчанию должен не вызываться.

1 Ответ

2 голосов
/ 20 августа 2011

Метод 1: va_args

Если вы согласны сделать бар POD, это можно сделать с помощью va_args:

#include <stdarg.h>

struct bar {
  void * ptr;
};

template<class T, int N>
struct foo
{
  foo(...)  { // here the arg list should be passed
    va_list ap;
    va_start(ap, N);

    for (int i = 0; i < N; ++i) {
      store[i] = va_arg(ap, T);
    }
    va_end(ap);
  }

  T store[N];
};

int main()
{
  foo<bar,2> f(bar(),bar());
}

Хотя это и не здорово - вам нужно слишком сильно доверять вызывающему абоненту, и требование POD может быть весьма ограничивающим.

Метод 2: диапазон

Если вы согласны сделать ваш тип T и конструируемым, и назначаемым по умолчанию, вы можете использовать этот метод:

#include <assert.h>
#include <stdlib.h>

struct bar {
  bar(void * ptr): ptr(ptr) {}
  bar() {}
  void * ptr;
};

template<class T, int N>
struct foo
{
  foo(T *begin, const T *end)  { // here the arg list should be passed
    // Normally I'd use std::copy here!
    int i = 0;
    while (begin != end) {
       assert(i < N);
       store[i] = *begin++;
    }
  }

  T store[N];
};

int main()
{
  bar b[2]={NULL,NULL};
  foo<bar,2> f(&b[0], &b[sizeof(b)/sizeof(bar)]);
}

Это не совсем гладко - у вас есть и массив, и экземпляр вашего объекта, но вы можете сделать массив static const и, по крайней мере, хорошо скрыть его от остальной части кода.

Способ 3: приемы перегрузки операторов

Вы также можете использовать трюк с operator,, чтобы свести все элементы к одному параметру, что в IIRC аналогично тому, что делает Boost.Assign .

...