Заполните контейнер параметрами шаблона - PullRequest
1 голос
/ 17 мая 2010

Я хочу заполнить параметры шаблона, переданные в шаблон переменной, в массив фиксированной длины.Для этого я написал следующие шаблоны вспомогательных функций

template<typename ForwardIterator, typename T>
void fill(ForwardIterator i) { }

template<typename ForwardIterator, typename T, T head, T... tail>
void fill(ForwardIterator i) {
  *i = head;
  fill<ForwardIterator, T, tail...>(++i);
}

следующий шаблон класса

template<typename T, T... args>
struct params_to_array;

template<typename T, T last>
struct params_to_array<T, last> {
  static const std::size_t SIZE = 1;
  typedef std::array<T, SIZE> array_type;

  static const array_type params;

private:
  void init_params() {
    array_type result;
    fill<typename array_type::iterator, T, head, tail...>(result.begin());
    return result;
  }
};

template<typename T, T head, T... tail>
struct params_to_array<T, head, tail...> {
  static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;
  typedef std::array<T, SIZE> array_type;

  static const array_type params;

private:
  void init_params() {
    array_type result;
    fill<typename array_type::iterator, T, last>(result.begin());
    return result;
  }
};

и инициализировал статические константы с помощью

template<typename T, T last>
const typename param_to_array<T, last>::array_type
param_to_array<T, last>::params =
  param_to_array<T, last>::init_params();

и

template<typename T, T head, T... tail>
const typename param_to_array<T, head, tail...>::array_type
param_to_array<T, head, tail...>::params =
  param_to_array<T, head, tail...>::init_params();

Теперь массив

param_to_array<int, 1, 3, 4>::params

представляет собой std::array<int, 3> и содержит значения 1, 3 и 4.Я думаю, что должен быть более простой способ добиться такого поведения.Любые предложения?

Редактировать: Как предложил Ной Робертс в своем ответе, я изменил свою программу следующим образом: я написал новую структуру, подсчитывающую элементы в списке параметров:

template<typename T, T... args>
struct count;

template<typename T, T head, T... tail>
struct count<T, head, tail...> {
  static const std::size_t value = count<T, tail...>::value + 1;
};

template<typename T, T last>
stuct count<T, last> {
  static const std::size_t value = 1;
};

и написал следующую функцию

template<typename T, T... args>
std::array<T, count<T, args...>::value>
params_to_array() {
  std::array<T, count<T, args...>::value> result;
  fill<typename std::array<T, count<T, args...>::value>::iterator,
       T, args...>(result.begin());
  return result;
}

Теперь я получаю с

params_to_array<int, 10, 20, 30>()

a std::array<int, 3> с содержанием 10, 20 и 30.Есть еще предложения?

Ответы [ 2 ]

2 голосов
/ 18 мая 2010

Нет необходимости подсчитывать количество типов в пакете параметров вручную, для этого предназначен оператор sizeof.... Кроме того, я бы сделал тип итератора для fill() франшизы, нет необходимости указывать его явно:

template<typename T, typename FwdIt>
void fill(FwdIt it) { }

template<typename T, T head, T... tail, typename FwdIt>
void fill(FwdIt it) {
    *it = head;
    fill<T, tail...>(++it);
}

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() {
    std::array<T, sizeof...(args)> a;
    fill<T, args...>(a.begin());
    return a;
};

Пакеты параметров, однако, также можно расширять в контексте списка инициализаторов, что делает fill() избыточным:

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() {
    std::array<T, sizeof...(args)> a = {{args...}};
    return a;
};
1 голос
/ 17 мая 2010

Единственная причина, по которой я вижу специализацию для конечной точки в param_to_array, - это строка:

static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1;

Поскольку ваша метафункция params_to_array создает массив, хотя вы собираетесь в итоге создавать экземпляры массивов размера N, N-1, ...., 1. Таким образом, я думаю, что ваш объект мог бы использовать некоторую помощь из композиции и единственной ответственности править. Создайте другую метафункцию, которая может считать элементы в списке параметров, и используйте ее вместо этого метода. Тогда вы можете избавиться от этой рекурсии как минимум в params_to_array.

...