При совмещении неявного и явного захвата первым элементом в списке захвата должен быть символ & или =. Эти символы задают режим захвата по умолчанию: по ссылке или по значению соответственно.

При совмещении неявного и явного захвата явно захваченные переменные должны использовать дополнительную форму. Таким образом, при неявном захвате по ссылке (с использованием &) явно именованные переменные должны захватываться по значению; следовательно, их именам не может предшествовать символ &. И наоборот, при неявном захвате по значению (с использованием =) явно именованным переменным должен предшествовать символ &, означающий, что они должны быть захвачены по ссылке.

Изменяемые лямбда-выражения

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

void fcn3() {

 size_t v1 = 42; // локальная переменная

 // f может изменить значение захваченных переменных

 auto f = [v1]() mutable { return ++v1; };

 v1 = 0;

 auto j = f(); // j = 43

}

Может ли захваченная по ссылке переменная быть изменена, зависит только от того, ссылается ли она на константный или неконстантный тип:

void fcn4() {

 size_t v1 = 42; // локальная переменная

 // v1 - ссылка на неконстантную переменную

 // эту переменную можно изменить в f2 при помощи ссылки

 auto f2 = [&v1] { return ++v1; };

 v1 = 0;

 auto j = f2(); // j = 1

}

Определение типа возвращаемого значения лямбда-выражения

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

В качестве примера используем библиотечный алгоритм transform() и лямбда-выражение для замены каждого отрицательного значения в последовательности его абсолютным значением:

transform(vi.begin(), vi.end(), vi.begin(),

          [](int i) { return i < 0 ? -i : i; });

Функция transform() получает три итератора и вызываемый объект. Первые два итератора обозначают исходную последовательность, третий итератор — назначение. Алгоритм вызывает переданный ему вызываемый объект для каждого элемента исходной последовательности и записывает результат по назначению. Как и в данном примере, итератор назначения может быть тем же, обозначающим начало ввода. Когда исходный итератор и итератор назначения совпадают, алгоритм transform() заменяет каждый элемент в исходном диапазоне результатом вызова вызываемого объекта для этого элемента.

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

Но если написать на первый взгляд эквивалентную программу, используя оператор if, то код не будет компилироваться:

// ошибка: нельзя вывести тип возвращаемого значения лямбда-выражения

transform(vi.begin(), vi.end(), vi.begin(),

          [](int i) {if (i < 0) return -i; else return i; });

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

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

transform(vi.begin(), vi.end(), vi.begin(),

          [](int i) -> int

           { if (i < 0) return -i; else return i; });

В данном случае четвертым аргументом функции transform() является лямбда-выражение с пустым списком захвата, единственным параметром типа int и возвращаемым значением типа int. Его телом является оператор if, возвращающий абсолютное значение параметра.

Упражнения раздела 10.3.3
Перейти на страницу:

Похожие книги