Заполните контейнер параметрами шаблона

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

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>()

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


person phlipsy    schedule 17.05.2010    source источник


Ответы (2)


Нет необходимости вручную подсчитывать количество типов в пакете параметров, для этого нужен оператор 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;
};
person Georg Fritzsche    schedule 18.05.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.

person Edward Strange    schedule 17.05.2010
comment
Ты прав! Я изменил (и таким образом упростил) свою программу, и она сработала. +1! - person phlipsy; 17.05.2010
comment
Нет необходимости в другой мета-функции, просто используйте вместо этого sizeof...(parameterPack) в C ++ 0x :) - person Georg Fritzsche; 19.05.2010