Добавить все параметры с расширением пакета параметров

Допустим, у меня есть вариативный шаблон с параметрами int.... Например, такая функция:

template<int... t>
int add(){
    return t... + ???
}

Все, что должен сделать метод, это добавить все параметры. Этого можно легко добиться, используя рекурсивные вариативные шаблоны. Однако возможно ли также выразить это (или что-то подобное, например, использовать другие бинарные операторы для агрегирования всех параметров шаблона) с помощью расширения пакета параметров?


person gexicide    schedule 13.05.2014    source источник
comment
Нет. Просто делайте это так, как это может быть легко достигнуто.   -  person R. Martinho Fernandes    schedule 13.05.2014
comment
Хорошо, я просто подумал, что это может быть еще проще и понятнее с расширением пакета параметров :)   -  person gexicide    schedule 13.05.2014
comment
Проблема с другими решениями заключается в том, что они вычисляют дополнительное время выполнения.   -  person Peregring-lk    schedule 14.05.2014
comment
@Peregring-lk: Вы правы, это важный факт!   -  person gexicide    schedule 14.05.2014


Ответы (2)


Да, используя трюк, которому я научился у @Xeo в гостиной. Первоначально я использовал его для создания вариативной функции шаблона «печать».

#include <iostream>

template<int... ints>
int add()
{
  int result = 0;
  using expand_variadic_pack  = int[]; // dirty trick, see below
  (void)expand_variadic_pack{0, ((result += ints), void(), 0)... };
  // first void: silence variable unused warning
  // uses braced-init-list initialization rules, which evaluates
  //  the elements inside a braced-init-list IN ORDER, to repetetively
  //  execute a certain operation
  // second void is to prevent malicious "operator," overloads, which
  //  cannot exist for void types
  // 0 at the end is to handle empty variadic pack (zero-size array initializer is illegal.
  return result;
}

int main()
{
  std::cout << add<1,2,3,4>() << '\n';
}

Это работает на каждом компиляторе с достойной поддержкой С++ 11 (GCC 4.8+, Clang 3.2+, MSVS2013,...)

person rubenvb    schedule 13.05.2014
comment
Не уверен, смеяться или плакать - person Lightness Races in Orbit; 13.05.2014
comment
@Lightness наверняка вы уже злоупотребляли побочными эффектами выражений в С++. - person rubenvb; 13.05.2014
comment
Конечно! ???????????????????????? - person Lightness Races in Orbit; 13.05.2014
comment
Это также должно работать (и выглядеть немного чище) с auto a = {(ret += ints)... }; (void)a; - person PlasmaHH; 14.05.2014
comment
Для чего используется первый 0 в brace-init-list? - person Peregring-lk; 13.05.2015
comment
@Peregring-lk, если пакет параметров пуст, инициализируется массив нулевого размера, что является недопустимым. Для более подробного объяснения того, что на самом деле происходит, см. этот ответ. - person rubenvb; 14.05.2015
comment
Этот подход также работает для вариативных входных параметров, например: template<typename... T> int add(T... ints): ideone.com/UtS43M - person Remy Lebeau; 27.03.2020

Один из возможных вариантов, в котором используются лямбда и std::accumulate:

#include <array>
#include <numeric>

template <int... t>
int add()
{
    return [](const std::array<int, sizeof...(t)>& a)
    {
        return std::accumulate(a.begin(), a.end(), 0);
    }({t...});
}
person Constructor    schedule 13.05.2014
comment
Этот выглядит чистым и гораздо менее хакерским! К сожалению, вычисления вряд ли будут оптимизированы во время компиляции. - person Tigran Saluev; 16.06.2016