Вместо того чтобы постоянно писать собственные предикаты, можно foo
" и заканчиваются словом "bar
", можно просто выбрать уже существующие предикаты и И
. В данном разделе мы будем работать с лямбда-выражениями, чтобы найти удобный способ сделать это.
Как это делается
В этом примере мы реализуем очень простые предикаты для фильтрации строк, а затем объединим их с помощью небольшой вспомогательной функции, которая создаст их комбинацию в обобщенном виде.
1. Как обычно, сначала включим несколько заголовочных файлов:
#include
#include
#include
#include
#include
2. Поскольку они понадобятся нам в дальнейшем, реализуем две простые функции-предиката. Одна из них говорит о том, начинается ли строка с символа 'a'
, а вторая — заканчивается ли строка символом 'b'
:
static bool begins_with_a (const std::string &s)
{
return s.find("a") == 0;
}
static bool ends_with_b (const std::string &s)
{
return s.rfind("b") == s.length() - 1;
}
3. Теперь реализуем вспомогательную функцию и назовем ее combine
. Она принимает бинарную функцию в качестве первого параметра — это может быть, например, логическое И
либо логическое ИЛИ
. Затем она принимает два других параметра, представляющих собой две функции-предиката, которые нужно объединить:
template
auto combine(F binary_func, A a, B b)
{
4. Просто возвращаем лямбда-выражение, которое захватывает новую
return [=](auto param) {
return binary_func(a(param), b(param));
};
}
5. Укажем, что будем использовать пространство имен std
с целью сэкономить немного времени при написании функции main
:
using namespace std;
6. Теперь объединим две функции-предиката в другую функцию-предикат, говорящую, начинается ли заданная строка с символа a
и заканчивается ли символом b
, как, например, строки "ab"
или "axxxb"
. На роль бинарной функции выбираем std::logical_and
. Это шаблонный класс, экземпляр которого нужно создавать, вследствие чего будем использовать его вместе с фигурными скобками. Обратите внимание: мы не предоставляем дополнительный параметр шаблона, поскольку для данного класса он по умолчанию будет равен void
. Эта специализация класса самостоятельно выводит все типы параметров:
int main()
{
auto a_xxx_b (combine(
logical_and<>{},
begins_with_a, ends_with_b));
7. Итерируем по стандартному потоку ввода и выводим на экран все слова, которые удовлетворяют условиям предиката:
copy_if(istream_iterator
ostream_iterator
a_xxx_b);
cout << '\n';
}
8. Компиляция и запуск программы дадут следующий результат. Мы передаем программе четыре слова, но только два из них удовлетворяют условиям предиката:
$ echo "ac cb ab axxxb" | ./combine
ab, axxxb,
Дополнительная информация
Библиотека STL уже предоставляет несколько функциональных объектов наподобие std::logical_and
, std::logical_or
, а также множество других, поэтому не нужно реализовывать их в каждом проекте. Ознакомиться со справочным материалом по С++ и исследовать доступные варианты можно на http://en.cppreference.com/w/cpp/utility/functional.
Вызываем несколько функций с одинаковыми входными данными
Существует множество задач, чьи решения требуют написания повторяющегося кода. Большую его часть можно легко заменить лямбда-выражениями, и очень просто создать вспомогательную функцию, которая будет оборачивать подобные повторяющиеся задачи.
В данном разделе мы поработаем с лямбда-выражениями, чтобы направить один вызов функции со всеми его параметрами нескольким получателям. Мы сделаем это, не задействовав никаких дополнительных структур данных, так что перед компилятором будет стоять простая задача: сгенерировать бинарный файл без лишних затрат.
Как это делается
В этом примере мы напишем вспомогательную функцию для работы с лямбда-выражениями, которая направляет один вызов нескольким объектам, и еще одну такую функцию, направляющую один вызов нескольким функциям. Эту комбинацию мы используем в нашем примере, чтобы вывести на экран одно сообщение с помощью разных функций-принтеров.
1. Включим заголовочный файл, необходимый для вывода данных на экран: