Bool operator() ( intvalue ) const

{

returnvalue >= minRange && value <= maxRange;

}

private:

const intminRange, maxRange;

}

std::count_if(

v.begin(), v.end(),

Labmda_1( minRange, maxRange ) ()

);

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

#include <map>

#include <string>

#include <iostream>

#include <algorithm>

intmain ()

{

typedefstd::map< std::string, double> Prices;

Prices prices;

prices[ "Apple" ] = 9.50;

prices[ "Orange" ] = 8.30;

prices[ "Banana" ] = 2.20;

doublemaximumPriceLimit;

std::cout << "Enter price limit: ";

std::cin >> maximumPriceLimit;

std::for_each(

prices.begin(), prices.end(),

[ maximumPriceLimit ] ( constPrices::value_type & v )

{

if( v.second > maximumPriceLimit )

std::cout << "Item " << v.first << " is too expensive" << std::endl;

}

);

}

Ниже представлен вывод программы, если ввести в качестве лимита стоимость в 5.00:

bool operator() ( intvalue ) const - student2.ru

В ряде других случаев лямбда-выражение должно ссылаться на внешние данные не по значению, а по ссылке. Одна из таких возможных причин - нежелание копировать большие объемы данных. Чтобы указать, что переменная захватывается по ссылке, нужно указать знак амперсанда перед именем захватываемой переменной. Тогда в сгенерированной схеме захваченные данные также будут храниться по ссылке.

В приведенной ниже программе задается набор цен на продукты, а также заказ - другое отображение, ключ которого - название продукта, а значение - заказанное количество. Программа подсчитывает общую стоимость заказа при помощи алгоритма std::accumulate и лямбда-выражения, вычисляющего стоимость конкретной записи в заказе. При этом, набор цен на продукты захватывается лямбда-выражением по ссылке:

#include <map>

#include <string>

#include <iostream>

#include <algorithm>

#include <numeric>

intmain ()

{

typedefstd::map< std::string, double > Prices;

Prices prices;

prices[ "Apple" ] = 9.50;

prices[ "Orange" ] = 8.30;

prices[ "Banana" ] = 2.20;

typedefstd::map< std::string, double > Order;

Order myOrder;

myOrder[ "Apple" ] = 2.5;

myOrder[ "Orange" ] = 1.3;

myOrder[ "Banana" ] = 0.6;

doubleorderTotalCost =

std::accumulate(

myOrder.begin(), myOrder.end(),

0.0,

[ & prices ] ( doubletotal, Order::value_type vt )

{

returntotal + vt.second * prices[ vt.first ];

}

);

std::cout << "Order totally takes: " << orderTotalCost << std::endl;

}

bool operator() ( intvalue ) const - student2.ru

Если в лямбда-выражении нужно захватывать много ссылок, можно использовать объявление захвата ссылок по умолчанию. Приведенный ниже фрагмент также считает сумму заказа, однако при помощи алгоритма std::for_each. При этом захватывается две ссылки - переменная для суммы-результата и набор цен на продукты:

doubleorderTotalCost = 0.0;

std::for_each(

myOrder.begin(), myOrder.end(),

[ & ] ( constOrder::value_type & vt )

{

orderTotalCost += vt.second * prices[ vt.first ];

}

);

Аналогично, если лямбда-выражение нуждается в захвате большого количества переменных по значению, можно использовать подобный синтаксис с символом “=” вместо “&”..

Имеется также смешанный синтаксис, когда одни переменные захватываются по ссылке, а другие - по значению. Приведенная ниже модификация подсчитывает стоимость части заказа, где цена продукта превышает пользовательский лимит. Переменная-результат и набор цен на продукты захватываются по ссылке по умолчанию, а переменная с лимитом - по значению, как указано явно.

doubleorderTotalCost = 0.0;

std::for_each(

myOrder.begin(), myOrder.end(),

[ &, maxPriceLimit ] ( constOrder::value_type & vt )

{
doubleprice = prices[ vt.first ];

if( price > maxPriceLimit )

orderTotalCost += vt.second * prices[ vt.first ];

}

);

Комплексный пример

Применим полученные знания о стандартных алгоритмах, ассоциативных контейнерах и лямбда-выражениях для реальной практической задачи. Пусть имеется зарплатная ведомость организации в виде отображения, где ключ представляет собой фамилию сотрудника, а значение - его зарплата “чистыми”, т.е., после уплаты всех предусмотренных в государстве налогов. Организация желает знать какую общую сумму средств необходимо потратить вместе с налоговыми отчислениями, чтобы выдать зарплату всем сотрудникам.

Для улучшения понимания задачи, кратко рассмотрим типичный принцип расчета налоговых отчислений с заработной платы, соответствующий законодательству Украины на момент 2016г. (к сожалению, налоговые правила меняются часто, и пример приходится регулярно обновлять). Каждому сотруднику начисляется так называемая “грязная” заработная плата, или зарплата-брутто. С этой суммы удерживается подоходный налог (18%), а также, с недавних пор, военный сбор (1.5%). Сотруднику выплачивается “чистая” заработная плата, или зарплата-нетто, за вычетом этих налогов. Дополнительно, организация уплачивает с зарплаты-брутто еще один налог - единый социальный взнос (обычно, 22%, но встречаются и другие ставки, в зависимости от нюансов видов деятельности и собственности организации).

Например, пусть зарплата-брутто сотрудника равна 4000грн. С этой суммы взимается подоходный налог 720 грн.. (18%) и военный сбор 60грн (1.5%). Выдается зарплата-нетто, равная 4000-720-60, т.е. 3220 грн. Дополнительно, организация оплачивает единый социальный взнос - 22% от 4000грн, или 880 грн. Таким образом, для зарплаты-нетто в 3220 грн. уплачивается в общей сложности 1660 грн. налогов, что составляет приблизительно 51.5% от зарплаты-нетто.

В рассматриваемой задаче имеется таблица зарплат-нетто каждого из сотрудников. Соответственно, цель программы - подсчитать сумму всех зарплат-брутто + единый социальный взнос.

#include <unordered_map>

#include <algorithm>

#include <iostream>

#include <string>

#include <functional>

intmain ()

{

typedefstd::unordered_map< std::string, double> Salaries;

Salaries salaries;

salaries[ "Ivanov" ] = 1000.0;

salaries[ "Petrov" ] = 1200.0;

salaries[ "Sidorov" ] = 800.0;

const doublepersonalIncomeTax = 0.18;

const doublesalarySocialTax = 0.22;

const doublemilitaryTax = 0.015;

doubletotalSalaryWithTaxes = 0.0;

std::for_each(

salaries.cbegin(), salaries.cend(),

[=, & totalSalaryWithTaxes ] ( constSalaries::value_type & v )

{

doublenetto = v.second;

doublepersonalBrutto = netto /
( 1.0 - personalIncomeTax - militaryTax );

doubletotalBrutto = personalBrutto * ( 1 + salarySocialTax );

totalSalaryWithTaxes += totalBrutto;

}

);

std::cout << "Total salary + taxes to pay: " << totalSalaryWithTaxes << std::endl;

}

Полные примеры из лекции

https://github.com/zaychenko-sergei/oop-samples/tree/master/lec8

Выводы

В данной лекции было продолжено изучение возможностей стандартной библиотеки шаблонов.

В первой половине лекции было введено понятие вызываемой сущности - абстракции, объединяющей конструкции языка, которые можно вызывать подобно функциям с передачей аргументов и получением результата. Была показана роль вызываемых сущностей для модификации поведения стандартных алгоритмов. Вызываемые сущности могут принимать различные формы - указатели на функции, функциональные объекты, наконец лямбда-выражения, максимально удачно вписывающиеся в синтаксис языка. Рассматривались существующие функторы, определенные в стандартной библиотеке, в частности, функторы для всех основных операторов, а также функтор std::bind, предназначенный для связывания других функторов в более сложные. Также речь зашла об универсальной вызываемой сущности std::function, которая позволяет легко состыковать обыкновенный код, не использующий шаблоны, с многообразием форм вызываемых сущностей.

Во второй половине лекции речь зашла об ассоциативных контейнерах. Рассматривались особенности работы с отображениями и множествами на основе бинарных деревьев поиска и хэш-таблиц. Были продемонстрированы возможности стыковки пользовательских типов для ключей, не нарушающие принципы работы базовых структур данных.

Наконец, были показаны дополнительные возможности лямбда-выражений, связанные с захватом внешних переменных в режимах по значению и по ссылке.

.

Наши рекомендации