Выбрать главу

В нашем выражении свертки мы всегда передаем в функцию std::count начальный и конечный итераторы одного диапазона параметров. Однако в качестве третьего параметра мы всякий раз отправляем один параметр из пакета. В конечном счете функция складывает все результаты и возвращает их вызывающей стороне.

Ее можно использовать следующим образом:

std::vector<int> v {1, 2, 3, 4, 5};

matches(v, 2, 5);                  // возвращает 2

matches(v, 100, 200);              // возвращает 0

matches("abcdefg", 'x', 'y', 'z'); // возвращает 0

matches("abcdefg", 'a', 'd', 'f'); // возвращает 3

Как видите, вспомогательная функция matches довольно гибкая — ее можно вызвать для векторов или даже строк. Она также будет работать для списка инициализаторов, контейнеров std::list, std::array, std::set и прочих!

Проверка успешности вставки нескольких элементов в множество

Напишем вспомогательную функцию, которая добавляет произвольное количество параметров в контейнер std::set и возвращает булево значение, показывающее, успешно ли прошла операция:

template <typename T, typename ... Ts>

bool insert_all(T &set, Ts ... ts)

{

  return (set.insert(ts).second && ...);

}

Как же это работает? Функция insert контейнера std::set имеет следующую сигнатуру:

std::pair<iterator, bool> insert(const value_type& value);

Документация гласит, что при попытке вставить элемент функция insert вернет пару из iterator и переменной bool. Если вставка пройдет успешно, значение переменной будет равно true. Итератор же в этом случае укажет на новый элемент множества, а в противном случае — на существующий элемент, который помешал вставке.

Наша вспомогательная функция после вставки обращается к полю .second. Оно содержит переменную bool, которая показывает, была ли вставка успешной. Если все полученные пары имеют значение true, то все вставки прошли успешно. Свертка объединяет все результаты вставки с помощью оператора && и возвращает результат.

Контейнер можно использовать следующим образом:

std::set<int> my_set {1, 2, 3};

insert_all(my_set, 4, 5, 6); // Возвращает true

insert_all(my_set, 7, 8, 2); // Возвращает false, поскольку 2 уже присутствует

Обратите внимание: если мы попробуем вставить, например, три элемента, но в процессе окажется, что второй элемент вставить нельзя, свертка && ... досрочно прекратит работать и оставшиеся элементы не будут добавлены:

std::set<int> my_set {1, 2, 3};

insert_all(my_set, 4, 2, 5); // Возвращает false

// теперь множество содержит значения {1, 2, 3, 4}, без 5!

Проверка попадания всех параметров в заданный диапазон

Поскольку можно убедиться, что одна из переменных находится в конкретном диапазоне, можно сделать то же самое для нескольких переменных с помощью выражений свертки:

template <typename T, typename Ts>

bool within(T min, T max, Ts ts)

{

  return ((min <= ts && ts <= max) && ...);

}

Выражение (min <= ts && ts <= max) определяет, находится ли каждый элемент пакета параметров в диапазоне между min и max (включая min и max). Мы выбрали оператор &&, чтобы свести все результаты булева типа к одному, который имеет значение true только в том случае, если все отдельные результаты имеют такое же значение.

Это работает следующим образом:

within( 10, 20, 1, 15, 30);     // --> false

within( 10, 20, 11, 12, 13);    // --> true

within(5.0, 5.5, 5.1, 5.2, 5.3) // --> true

Что интересно: эта функция очень гибкая, поскольку единственным требованием, которое она предъявляет к типам, служит возможность сравнения экземпляров с помощью оператора <=. Это требование выполняется, например, типом std::string:

std::string aaa {"aaa"};

std::string bcd {"bcd"};

std::string def {"def"};