Лямбда-функції в c (стандарт з 11)

Приклад використання лямбда-функції в C ++

Якщо ви не знайомі з синтаксисом []. то це лямбда-функція.

Мова С ++ містить корисні вбудовані функції, такі як std :: for_each і std :: transform. які дійсно потрібні і необхідні. На жаль, використання цих функцій досить громіздко і незручно, особливо якщо функтор, який ви застосовуєте, є унікальним для конкретної функції.

void func (std :: vector v)

std :: for_each (v.begin (), v.end (), f);

Якщо ви використовуєте об'єкт f тільки один раз і тільки в конкретному місці, то писати цілий клас (або структуру, як в прикладі) тільки для того, щоб виконати тривіальний код - це явне надмірність.

У C ++ 03 у вас може виникнути спокуса розташувати функтор поруч із зухвалим його кодом:

void func2 (std :: vector v)

std :: for_each (v.begin (), v.end (), f);

Однак таке написання не допускається, так як в C ++ 03 така функція не може бути передана в шаблон.

Приклад, в найпростішому вигляді:

void func3 (std :: vector v)

В даному прикладі лямбда-функція - це всього лише "синтаксичний цукор", за допомогою якого записується анонімний функтор. Запис "[]" означає, що у функції немає імені, вона безіменна, або, кажучи по-іншому, анонімна. Замість "[]" можна подумки підставляти ім'я "безимяннаяФункція", і думати про неї так: її виклик буде виконаний в той момент, коли до неї доходить покажчик на команду (якщо ви розумієте, як працює машинний код).

Типи значень, що повертаються

У найпростіших випадках тип значення лямбда-функції виводиться компілятором:

void func4 (std :: vector v)

std :: transform (v.begin (), v.end (), v.begin (),

Однак, коли ви починаєте писати більш складні лямбда-функції ви швидко зіткнетеся з випадком, коли повертається тип не може бути виведений компілятором, наприклад:

void func4 (std :: vector v)

std :: transform (v.begin (), v.end (), v.begin (),

У наведеному вище прикладі незрозуміло, який тип буде в разі повернення нуля - int або double, або ще якийсь.

Щоб вирішити цю проблему, можна вручну вказати повертається тип лямбда-функии, використовуючи синтаксис "-> тип":

void func4 (std :: vector v)

std :: transform (v.begin (), v.end (), v.begin (),

[] (Double d) -> double

Однак, лямбда-функція це не тільки анонімна функція, що викликається в місці свого використання. Крім іншого, лямбда-функція може використовувати змінні, доступні в її контексті. Тобто змінні, доступні в тому ж контексті де і описана лямбда-функції, доступні всередині лямбда-функції. Це називається "замикання".

Цитата з Вікіпедії:

Замикання (англ. Closure) в програмуванні - функція. в тілі якої присутні посилання на змінні, оголошені поза тілом цієї функції і не в якості її параметрів (а в навколишньому коді). Кажучи іншою мовою, замикання - функція, яка посилається на вільні змінні в своєму контексті.

Якщо ви хочете отримати доступ до зовнішніх змінним всередині лямбда-функції, можна використовувати вираз "[]", в якому потрібно вказати захоплювану зовнішню змінну, яку можна буде використовувати всередині лямбда-функції:

void func5 (std :: vector v, const double epsilon)

std :: transform (v.begin (), v.end (), v.begin (),

[Epsilon] (double d) -> double

if (d У цьому прикладі є пременися epsilon. яка є зовнішньою по відношенню до лямбда-функції. Вона захоплюється і використовується всередині функції. Можна вказати кілька захоплюваних змінних через кому.

Крім усього іншого, можна захоплювати не тільки змінну. Можна захоплювати посилання на змінну. Крім імен захоплюваних змінних, можна вказувати "правила захоплення", обозначамие "" і "=":

  • [Epsilon] - захоплення посилання на змінну;
  • [, Epsilon] - показує, що за замовчуванням захоплення змінних буде відбуватися за посиланням;
  • [=, epsilon] - показує, що за замовчуванням захоплення змінних буде відбуватися за значенням, але для змінної epsilon захоплення повинен проводитися за посиланням;
  • [X, y] - захоплення змінної x за значенням, і змінної y по посиланню.

Наступна фраза вище мого розуміння:

The generated operator () is const by default, with the implication that captures will be const when you access them by default. This has the effect that each call with the same input would produce the same result, however you can mark the lambda as mutable to request that the operator () that is produced is not const.