Шаблон для инициализатора переменной длины

Мне нужно семейство функций инициализации с переменным числом используемых значений. Я использую их для реализации операции сбора с библиотекой Eigen. Вот как я это делаю сейчас с одним шаблоном для каждой длины вектора:

template<typename T1, typename T2>
inline void gather (Array<T1,4,1> &to, const Array<T2,Dynamic,1> &from, const Array<int,4,1> &index) 
{
    to << from[index[0]], from[index[1]], from[index[2]], from[index[3]];
}

template<typename T1, typename T2>
inline void gather (Array<T1,6,1> &to, const Array<T2,Dynamic,1> &from, const Array<int,6,1> &index) 
{
    to << from[index[0]], from[index[1]], from[index[2]], from[index[3]], from[index[4]], from[index[5]];
}

Есть ли способ заменить более длинный список шаблонов, как указано выше, одним шаблоном, параметризованным параметром длины (4 и 6 во фрагменте выше)? Если да, то можно ли это сделать с помощью спецификаций языка до С++ 11 (я использую Visual Studio 2010)?

Я хотел бы сохранить синтаксис значений, разделенных запятыми, так как я надеюсь, что в некоторых случаях это может привести к инициализации времени компиляции (const from и index). Хотя могу ошибаться в этом предположении. Список инициализаторов может иметь от 1 до 16 значений — не нужно беспокоиться о пустом списке.


person Paul Jurczak    schedule 14.11.2012    source источник
comment
Я так понимаю, вы ищете способ сделать это с помощью автоматического вывода, да? Кроме того, это должна быть цепочка вставки (до ‹‹ val ‹‹ val ‹‹ val..) или все запятые предназначены?   -  person WhozCraig    schedule 14.11.2012
comment
Запятые нужны - таков синтаксис инициализатора Eigen. Я надеюсь, что это производит инициализацию времени компиляции.   -  person Paul Jurczak    schedule 14.11.2012
comment
Возможно, это делает любую инициализацию во время компиляции, поскольку вы имеете дело с уже инициализированными данными.   -  person Xeo    schedule 14.11.2012
comment
@Xeo Вы имели в виду, что невозможно?   -  person Paul Jurczak    schedule 15.11.2012
comment
@Paul: Эээ... да. :( Проклятые опечатки, меняющие весь смысл. :)   -  person Xeo    schedule 15.11.2012


Ответы (2)


Не используйте синтаксис инициализатора запятой в этом параметре, это будет громоздко. Этот синтаксис используется для удобочитаемости при использовании литералов, что не в вашем случае.

Вместо этого я бы рекомендовал что-то вроде:

template<typename T1, typename T2, unsigned int SIZE, unsigned int INDEX>
struct gather {
   gather(Array<T1,SIZE,1> &to, 
          const Array<T2,Dynamic,1> &from, 
          const Array<int,SIZE,1> &index) 
   {
      to.col(INDEX) = from[index[INDEX]];
      gather<T1,T2,SIZE,INDEX+1>(to,from, index);
   }
};

template<typename T1, typename T2, unsigned int SIZE>
struct gather<T1,T2,SIZE,SIZE>{
    gather(Array<T1,SIZE,1> &to, 
           const Array<T2,Dynamic,1> &from, 
           const Array<int,SIZE,1> &index)
    {
    }
};

который прекрасно производит тот же эффект, но статически (без цикла).

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

person didierc    schedule 14.11.2012
comment
Кажется, что CommaInitializer не может выполнить инициализацию во время компиляции, поэтому подойдет это решение или даже решение цикла (ответ был удален). - person Paul Jurczak; 15.11.2012

Довольно сложно обобщить этот синтаксис на основе перегрузки оператора operator,, и результат в лучшем случае выглядит неуклюжим (если он работает). Я бы рекомендовал попробовать другие варианты (например, выбрать оператор MatrixBase::operator<<(DenseBase&)).

Если вы все еще хотите, вы должны распаковать скаляры один за другим:

template<typename T1, typename T2, class CI, int Current, int Height>
inline void gather (Array<T1,Height,1> &to, const Array<T2,Dynamic,1> &from, const Array<int,Height,1> &index, CI&& ci, std::integral_constant<int, Current>*)
{
  gather(to, from, index, (ci,from[index[Current]]), (std::integral_constant<int, Current+1>*)0);
}

template<typename T1, typename T2, class CI, int Height>
inline void gather (Array<T1,Height,1> &to, const Array<T2,Dynamic,1> &from, const Array<int,Height,1> &index, CI&& ci, std::integral_constant<int, Height>*) {}

template<typename T1, typename T2, int Height>
inline void gather (Array<T1,Height,1> &to, const Array<T2,Dynamic,1> &from, const Array<int,Height,1> &index) {
  gather(to, from, index, (to << index[from[0]]), (std::integral_constant<int, 1>*)0);
}

Некрасиво, и могут быть проблемы (вам нужно обработать значение Dynamic, нулевую высоту, если это возможно, могут быть проблемы с передачей CommaInitializers в рекурсию и т. д.)

Кроме того, он имеет линейную глубину инстанцирования шаблона (и, ИМХО, в данном случае это неизбежно).

person jpalecek    schedule 14.11.2012
comment
@jplacek Нулевые элементы не проблема - я отредактировал свой вопрос. Я согласен, это уродливо :-) Вдобавок ко всему, у меня есть лишь слабое представление о том, что он на самом деле делает. - person Paul Jurczak; 14.11.2012