template
auto sum(Ts ts)
{
return (ts + ...);
}
3. Теперь можно вызвать функцию следующим образом:
int the_sum {sum(1, 2, 3, 4, 5)}; // Значение: 15
4. Она работает не только с целочисленными типами; можно вызвать ее для любого типа, реализующего оператор +
std::string
:std::string a {"Hello "};
std::string b {"World"};
std::cout << sum(a, b) << '\n'; // Вывод: Hello World
Как это работает
Только что мы написали код, в котором с помощью простой рекурсии бинарный оператор (+
Подобное выражение называется
+
, –
, *
, /
, %
, ^
, &
, |
,=
<
, >
, <<
, >>
, +=
, –=
, *=
, /=
, %=
, ^=
, &=
, |=
, <<=
, >>=
, ==
, !=
, <=
, >=
, &&
, ||
, ,
, .*
, –>*
.Кстати, в нашем примере кода неважно, какую использовать конструкцию, (ts +
+ ts
);. Они обе работают так, как нужно. Однако между ними есть разница, которая может иметь значение в других случаях: если многоточие …
находится с В нашем примере с суммой левая унарная свертка разворачивается в конструкцию 1+(2+(3+(4+5)))
(((1+2)+3)+4)+5
. В зависимости от того, какой оператор используется, могут проявиться нюансы. При добавлении новых чисел ничего не меняется.Дополнительная информация
Если кто-то вызовет функцию sum()
0
.Это делается так:
template
auto sum(Ts ... ts)
{
return (ts + ... + 0);
}
Таким образом, вызов sum()
0
, а вызов sum(1, 2, 3)
— значение (1+(2+(3+0)))
. Подобные свертки с начальным значением называются Кроме того, обе конструкции, (ts + ... + 0)
(0 + ... + ts)
, работают как полагается, но такая бинарная свертка становится При использовании бинарных сверток для решения такой задачи, когда аргументы отсутствуют, очень важны
0
нейтральным элементом. Поэтому можно добавить 0
к любому выражению свертки с помощью операторов +
или –
. Если пакет параметров пуст, это приведет к возврату функцией значения 0
. С математической точки зрения это правильно. С точки зрения реализации нужно определить, что именно является правильным в зависимости от наших требований.Тот же принцип применяется и к умножению. Здесь нейтральным элементом станет 1
template
auto product(Ts ts)
{
return (ts * ... * 1);
}
Результат вызова product(2, 3)
6
, а результат вызова product()
без параметров равен 1
.В логических операторах И (&&)
ИЛИ (||)
появились &&
заменяется на true
, а свертка пустого пакета с оператором ||
— на false
.Еще один оператор, для которого определено значение по умолчанию, когда он используется для пустых пакетов параметров, — это оператор «запятая» (,
void()
.Давайте взглянем на другие вспомогательные функции, которые можно реализовать с помощью этих механизмов.
Соотнесение диапазонов и отдельных элементов
Как насчет функции, которая определяет, содержит ли диапазон
template
auto matches(const R& range, Ts ... ts)
{
return (std::count(std::begin(range), std::end(range), ts) + ...);
}