2.
3. Вполне возможно, что f
Гораздо более сложная функция for_each
1.
void
с помощью (void)std::initializer_list{...}
.2. Внутри инициализирующего выражения преобразует выражение f(xs)...
(f(xs),0)
. Это приводит к тому, что возвращаемое выражение 0
все еще помещается в список инициализаторов.3. Конструкция f(xs)
(f(xs),0)
. также преобразуется к типу void
, поэтому возвращаемое значение, если таковое существует, нигде не обрабатывается.Объединение этих особенностей, к сожалению, ведет к появлению уродливой конструкции, но она корректно работает и компилируется для множества объектов функций независимо от того, возвращают ли они какое-то значение.
Приятной особенностью описанного механизма является тот факт, что порядок вызовов функций будет сохраняться в
(void)выражение
reinterpret_cast(выражение)
, но данный вариант еще больше снизит удобочитаемость кода.Реализуем функцию transform_if с применением std::accumulate и лямбда-выражений
Большинство разработчиков, применяющих std::copy_if
std::transform
, могли задаваться вопросом, почему не существует функции std::transform_if
. Функция std::copy_if
копирует элементы из исходного диапазона по месту назначения, но опускает элементы, не соответствующие определенной пользователем функции-std::transform
безусловно копирует все элементы из исходного диапазона по месту назначения, но при этом преобразует их в процессе. Это происходит с помощью функции, которая определена пользователем и может выполнять как нечто простое (например, умножение чисел), так и полные преобразования к другим типам.Эти функции существуют достаточно давно, но функции std::transform_if
Как это делается
В этом примере мы создадим собственную функцию transform_if
std::accumulate
правильные объекты функций.1. Как и всегда, включим некоторые заголовочные файлы:
#include
#include
#include
2. Сначала реализуем функцию с именем map
std::accumulate
:template
auto map(T fn)
{
3. Мы будем возвращать объект функции, принимающий функцию reduce
reduce
для этого аккумулятора и преобразованной входной переменной fn
. Если это описание кажется вам слишком сложным — не волнуйтесь, далее мы соберем все вместе и посмотрим, как работают эти функции. return [=] (auto reduce_fn) {
return [=] (auto accum, auto input) {
return reduce_fn(accum, fn(input));
};
};
}
4. Теперь реализуем функцию filter
map
, но map
transform
. Вместо этого принимаем функцию-предикат и reduce
.template
auto filter(T predicate)
{
5. Два лямбда-выражения имеют такие же сигнатуры функций, что и выражения в функции map
reduce_fn
для входных данных или же получим доступ к аккумулятору, не внося никаких изменений. return [=] (auto reduce_fn) {
return [=] (auto accum, auto input) {