Лямбда-вирази у С++Лямбда-вираз у С++ — анонімна функція, яка підтримує стан між викликами і може отримати доступ до змінних зі своєї області видимості. Використовуючи лямбда-вирази, можна оголошувати функції в будь-якому місці коду. Лямбда-вирази підтримуються й іншими (окрім С++) мовами програмування, такими, як: C#, С, Python, PHP,Visual Basic .NET та іншими. Про лямбда-виразиБагато мов програмування підтримують концепцію анонімних функцій, які мають тіло, але не мають ім'я. Лямбда-вирази — це техніка програмування, пов'язана з анонімними функціями. Лямбда-вираз неявно задає клас об'єкта функції і створює функцію об'єкт цього класу. Приклад лямбда-виразу можна розглянути як параметр, що передається функції std::sort() #include <algorithm>
#include <cmath>
void abssort(float* x, unsigned N) {
std::sort(x, x + N,
// починається лямбда-вираз
[](float a, float b) {
return std::abs(a) < std::abs(b);
});
}
Об'єкти функцій і лямбда-виразівПри написанні коду часто виникає потреба використовувати вказівники на об'єкти чи на функції для вирішення деяких проблем і виконання обчислень, особливо при використанні алгоритмів STL. Вказівники на об'єкти і функції мають як переваги, так і недоліки. Для прикладу вказівники на функції мають мінімальне синтаксичне навантаження, але не зберігають свого стану між викликами, а об'єкти функції можуть зберігати стан, але вимагають додаткової синтаксичного навантаження. Лямбда-вирази поєднують переваги вказівників на функції і об'єктів функцій і уникають їхніх недоліків. Як і об'єкти функцій, лямбда-вирази гнучкі і можуть зберігати свій стан і, водночас, їх компактний синтаксис не вимагає визначення класу. З допомогою лямбда-виразів можна написати менш громіздкий і менш схильний до помилок код, ніж з допомогою еквівалентного об'єкта функції. Синтаксис лямбда-виразівГраматика лямбда-виразівНаступне формальне визначення виражає граматику зі стандарту ISO C++11 (елементи з opt у дужках є необов'язковими) lambda-introducer lambda-declarator(opt) compound-statement
Відповідні компоненти синаксису виражаються так: lambda-introducer: [ lambda-capture(opt) ] lambda-capture: capture-default capture-list capture-default , capture-list capture-default: & = capture-list: capture ... (opt) capture-list , capture ... (opt) capture: ідентифікатор & identifier this lambda-declarator: ( parameter-declaration-clause ) mutable(opt) Властивості лямбда-виразів[expr]
Наприклад, якщо тіло лямбда-виразу має доступ до змінної total по посиланню, а до змінної factor по значенню, наступні вирази еквівалентні: [&total, factor]
[factor, &total]
[&, factor]
[factor, &]
[=, &total]
[&total, =]
Часто люди припускаються таких помилок, зв'язаних з виразом фіксації: struct S { void f(int i); };
void S::f(int i) {
[&, i]{}; // OK
[&, &i]{}; // ERROR: i preceded by & when & is the default
[=, this]{}; // ERROR: this when = is the default
[i, i]{}; // ERROR: i repeated
}
Список параметрівСписок параметрів (lambda declarator) для лямбда-виразів є необов'язковим і нагадує список параметрів функцій. Лямбда-вираз також може приймати інший лямбда-вираз як параметр. Специфікація виключних ситуаційМожна використовувати специфікацію виключень throw(), щоб вказати, що лямбда-вираз не створює виключних ситуацій. Як і в випадку зі звичайними функціями, компілятор С++ створює попередження, якщо лямбда-вираз оголошує специфікацію виключень throw() і тіло лямбда-функції викликає виключну ситуацію, як показано в наступному прикладі: // throw_lambda_expression.cpp
// compile with: /W4 /EHsc
int main() // C4297 expected
{
[]() throw() { throw 5; }();
}
Значення, що повертаєтьсяМожна опустити вираз, що повертає значення у лямбда-виразі, якщо тіло лямбда-функції складається з одного return, або нічого не повертає. Якщо лямбда-вираз складається з одного оператора return, компілятор знаходить тип значення, що повертається з return-виразу, в противному випадку повертає значення void. auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return{ 1, 2 }; }; // ERROR: return type is void, deducing
// return type from braced-init-list not valid
Тіло лямбда-виразуТіло лямбда-виразу може мати доступ до таких змінних:
Крім того лямбда-вираз може мати доступ до змінних, які воно фіксує ([]) з зовнішньої області видимості. Явно за допомогою [expr], або неявно. Тіло лямбда-виразу використовує значення за замовчуванням для доступу до неявно зафіксованих змінних. Наступний приклад демонструє фіксацію n явно по значенню, а m — неявно по посиланню. #include <iostream>
using namespace std;
int main()
{
int m = 0;
int n = 0;
[&, n] (int a) mutable { m = ++n + a; }(4);
cout << m << endl << n << endl;
}
цей приклад виводить на консоль такий результат: 5 0 Джерела інформації
Див. такожПосилання
|
Portal di Ensiklopedia Dunia