Статьи

C ++ лаконично: лямбда-выражения

Я предполагаю, что у вас есть опыт работы с лямбдами из C #, поэтому мы рассмотрим синтаксис, принятый в C ++. Все фрагменты кода из одного и того же файла в одном и том же примере.

Образец: LambdaSample \ LambdaSample.cpp

1
2
3
4
5
6
7
8
// Create a lambda-expression closure.
   auto lm1 = []()
   {
       wcout << L»No capture, parameterless lambda.»
   };
    
   // Invoke the lambda.
   lm1();
1
2
3
4
5
6
7
// Create a lambda closure with parameters.
   auto lm2 = [](int a, int b)
   {
       wcout << a << L» + » << b << » = » << (a + b) << endl;
   };
    
   lm2(3,4);

Конечный тип возврата здесь -> int после спецификации параметра.

1
2
3
4
5
6
7
8
// Create a lambda closure with a trailing return type.
   auto lm3 = [](int a, int b) -> int
   {
       wcout << a << L» % » << b << » = «;
       return a % b;
   };
    
   wcout << lm3(7, 5) << endl;

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
int a = 5;
       int b = 6;
       // Capture by copy all variables that are currently in the scope.
       // Note also that we do not need to capture the closure;
       // here we simply invoke the anonymous lambda with the
       // () after the closing brace.
       [=]()
       {
           wcout << a << L» + » << b << » = » << (a + b) << endl;
           //// It’s illegal to modify a here because we have
           //// captured by value and have not specified that
           //// this lambda should be treated as mutable.
           //a = 10;
       }();
    
       [=]() mutable -> void
       {
           wcout << a << L» + » << b << » = » << (a + b) << endl;
           // By marking this lambda as mutable, we can now modify a.
           // Since we are capturing by value, the modifications
           // will not propagate outside.
           a = 10;
       }();
    
       wcout << L»The value of a is » << a << L».»
    
       [&]()
       {
           wcout << a << L» + » << b << » = » << (a + b) << endl;
           // By capturing by reference, we now do not need
   // to mark this as mutable.
           // Because it is a reference, though, changes now
           // propagate out.
           a = 10;
       }();
    
       wcout << L»The value of a is » << a << L».»
    
       // Here we specify explicitly that we are capturing a by
       // value and b as a reference.
       [a,&b]()
       {
           b = 12;
           wcout << a << L» + » << b << » = » << (a + b) << endl;
       }();
    
       // Here we specify explicitly that we are capturing b as
       // a reference and that all other captures should be by
       // value.
       [=,&b]()
       {
           b = 15;
           wcout << a << L» + » << b << » = » << (a + b) << endl;
       }();
    
       // Here we specify explicitly that we are capturing a by
       // value and that all other captures should be by reference.
       [&,a]()
       {
           b = 18;
           wcout << a << L» + » << b << » = » << (a + b) << endl;
       }();

Когда вы используете лямбду в функции члена класса, вы не можете использовать захват по умолчанию по ссылке. Это потому, что лямбда будет снабжена указателем this, и его необходимо скопировать. Кроме того, при работе с умными указателями с подсчетом ссылок часто встречаются проблемы с лямбдами, содержащими ссылку на класс. Обычно вы никогда не вернетесь к нулевому количеству ссылок, что приведет к утечке памяти в вашей программе.

Если вы знакомы с лямбда-выражениями в C #, то вам не составит труда привыкнуть к синтаксису в C ++. В следующей статье мы рассмотрим стандартную библиотеку C ++.

Этот урок представляет собой главу из C ++ Succinctly , бесплатной книги от команды Syncfusion .