Добавете всички параметри с разширение на пакета с параметри

Помислете, че имам променлив шаблон с 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';
}

Това работи на всеки компилатор, който има прилична поддръжка на C++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 със сигурност сте злоупотребявали със страничните ефекти на изразите преди в c++. - 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