[](int i){std::cout << i << "\n";});

С возвращаемыми значениями всё почти так же просто. Если тело лямбда-функции состоит из единственного предложения return, то тип возвращаемого ей значения совпадает с типом возвращаемого выражения. Например, такую простую лямбда-функцию можно было бы использовать для проверки флага, ожидаемого условной переменной std::condition_variable (см. раздел 4.1.1).

Листинг А.4. Простая лямбда-функция с выводимым типом возвращаемого значения

std::condition_variable cond;

 bool data_ready;

 std::mutex m;

void wait_for_data() {

 std::unique_lock lk(m);

 cond.wait(lk, []{return data_ready;}); ←(1)

}

Тип значения, возвращаемого лямбда-функцией, которая передана cond.wait() (1), выводится из типа переменной data_ready, то есть совпадает с bool. Когда условная переменная получает сигнал, она вызывает эту лямбда-функцию, захватив предварительно мьютекс, и wait() возвращает управление, только если data_ready равно true.

Но что если невозможно написать тело лямбда-функции, так чтобы оно содержало единственное предложение return? В таком случае тип возвращаемого значения следует задать явно. Это можно сделать и тогда, когда тело функции состоит из единственного предложения return, но обязательно, если тело более сложное. Для задания типа возвращаемого значения нужно поставить после списка параметров функции стрелку (->), а за ней указать тип. Если лямбда-функция не имеет параметров, то список параметров (пустой) все равно необходим, иначе задать тип возвращаемого значения невозможно. Таким образом, предикат, проверяемый условной переменной, можно записать так:

cond.wait(lk, []()->bool{ return data_ready; });

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

cond.wait(lk, []()->bool {

 if (data_ready) {

  std::cout << "Данные готовы" << std::endl;

  return true;

 } else {

  std::cout <<

   "Данные не готовы, продолжаю ждать" << std::endl;

  return false;

 }

});

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

<p>A.5.1. Лямбда-функции, ссылающиеся на локальные переменные</p>

Лямбда-функции с лямбда-интродуктором вида [] не могут ссылаться на локальные переменные из объемлющей области видимости; им разрешено использовать только глобальные переменные и то, что передано в параметрах. Чтобы получить доступ к локальной переменной, ее нужно захватить (capture). Проще всего захватить все переменные в локальной области видимости, указав лямбда-интродуктор вида [=]. Теперь лямбда-функция может получить доступ к копиям локальных переменных на тот момент, когда эта функция была создана.

Рассмотрим этот механизм на примере следующей простой функции:

std::function make_offseter(int offset) {

 return [=](int j){return offset+j;};

}

При каждом вызове make_offseter с помощью обертки std::function<> создается новый содержащий лямбда-функцию объект. Возвращенная функция добавляет указанное смещение к любому переданному ей параметру. Например, следующая программа

int main() {

 std::function offset_42 = make_offseter(42);

 std::function offset_123 = make_offseter(123);

 std::cout <<

  offset_42(12) << "," << offset_123(12) << std::endl;

 std::cout <<

  offset_42(12) << "," << offset_123(12) << std::endl;

}

Перейти на страницу:

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