Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 128 129 130 131 132 133 134 135 136 ... 297
Перейти на страницу:

Единственными вызываемыми объектами, использованными до сих пор, были функции и указатели на функции (см. раздел 6.7). Есть еще два вида вызываемых объектов: классы, перегружающие оператор вызова функции (будут рассматриваться в разделе 14.8), и лямбда-выражения (lambda expression).

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

[список захвата](список параметров) -> тип возвращаемого значения

 {тело функции}

где список захвата (зачастую пустой) — это список локальных переменных, определенных в содержащей функции; тип возвращаемого значения, список параметров и тело функции — те же самые, что и у любой обычной функции. Однако, в отличие от обычных функций, для определения типа возвращаемого значения лямбда-выражения должны использовать замыкающий тип (см. раздел 6.3.3).

Список параметров и типа возвращаемого значения могут отсутствовать, но список захвата и тело функции должны быть всегда:

auto f = [] { return 42; };

Здесь f определено как вызываемый объект, не получающий никаких аргументов и возвращающий значение 42. Вызов лямбда-выражений происходит таким же способом, что и вызов функций, — при помощи оператора вызова:

cout << f() << endl; // выводит 42

Пропуск круглых скобок и списка параметров в лямбда-выражении эквивалентен определению пустого списка параметров. Следовательно, когда происходит вызов лямбда-выражения f, список аргументов оказывается пустым. Если пропущен тип возвращаемого значения, то выведенный тип возвращаемого значения лямбда-выражения будет зависеть от кода в теле функции. Если телом является только оператор return, тип возвращаемого значения выводится из типа возвращаемого выражения. В противном случае типом возвращаемого значения является void.

Лямбда-выражения, тела которых содержат нечто кроме одного оператора return, что не определяет тип возвращаемого значения, возвращают тип void.

Передача аргументов лямбда-выражению

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

Для примера передачи аргументов можно написать лямбда-выражение, ведущее себя как функция isShorter():

[](const string &a, const string &b)

 { return a.size() < b.size();}

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

Вызов функции stable_sort() можно переписать так, чтобы использовать это лямбда-выражение следующим образом:

// сортировать слова по размеру, поддерживая алфавитный порядок среди

// слов того же размера

stable_sort(words.begin(), words.end(),

            [](const string &a, const string &b)

             { return a.size() < b.size();});

Когда функция stable_sort() будет сравнивать два элемента, она вызовет данное лямбда-выражение.

Использование списка захвата

Теперь все готово для решения первоначальной задачи — создания вызываемого выражения, которое можно передать функции find_if(). Необходимо выражение, сравнивающее длину каждой строки в исходной последовательности со значением параметра sz функции biggies().

Хотя лямбда-выражение может присутствовать в функции, оно способно использовать локальные переменные этой функции, только заранее определив, какие из них предстоит использовать. Лямбда-выражение определяет подлежащие использованию локальные переменные, включив их в список захвата (capture list). Список захвата предписывает лямбда-выражению включить информацию, необходимую для доступа к этим переменным, в само лямбда-выражение.

В данном случае лямбда-выражение захватит переменную sz и будет иметь один параметр типа string. Тело лямбда-выражения сравнивает размер переданной строки с захваченным значением переменной sz:

[sz](const string &a)

 { return a.size () >= sz; };

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

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

// ошибка: sz не захвачена

[](const string &a)

 { return a.size() >= sz; };

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

Вызов функции find_if()

Используя это лямбда-выражение, можно найти первый элемент, размер которого не меньше sz:

// получить итератор на первый элемент, размер которого >= sz

auto wc = find_if(words.begin(), words.end(),

                  [sz](const string &a)

                   { return a.size() >= sz; });

Вызов функции find_if() возвращает итератор на первый элемент, длина которого не меньше sz, или на элемент words.end(), если такового элемента не существует.

Возвращенный функцией find_if() итератор можно использовать для вычисления количества элементов, расположенных между этим итератором и концом вектора words (см. раздел 3.4.2):

// вычислить количество элементов с размером >= sz

auto count = words.end() - wc;

cout << count << " " << make_plural(count, "word", "s")

     << " of length " << sz << " or longer" << endl;

Для вывода в сообщении слова word или words, в зависимости от того, равен ли размер 1, оператор вывода вызывает функцию make_plural() (см. раздел 6.3.2).

Алгоритм for_each()

Последняя часть задачи — вывод тех элементов вектора words, длина которых не меньше sz. Для этого используем алгоритм for_each(), получающий вызываемый объект и вызывающий его для каждого элемента в исходном диапазоне:

// вывести слова, размер которых равен или больше заданного, разделяя

// их пробелами

for_each(wc, words.end(),

         [](const string &s) {cout << s << " ";});

cout << endl;

Список захвата этого лямбда-выражения пуст, но все же его тело использует два имени: его собственный параметр s и cout.

Список захвата пуст, поскольку он используется только для нестатических переменных, определенных в окружающей функции. Лямбда-выражение вполне может использовать имена, определенные вне той функции, в которой присутствует лямбда-выражение. В данном случае имя cout не локально определено в функции biggies(), оно определено в заголовке iostream. Пока заголовок iostream находится в области видимости функции biggies(), данное лямбда-выражение может использовать имя cout.

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

Объединив все вместе

Теперь, изучив элементы программы подробно, рассмотрим ее в целом:

void biggies(vector<string> &words,

             vector<string>::size_type sz) {

 elimDups(words); // расположить слова в алфавитном порядке

                  // и удалить дубликаты

 // пересортировать по длине, поддерживая алфавитный порядок среди слов

1 ... 128 129 130 131 132 133 134 135 136 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии