Understand c++11 Lambda expressions _C language _ Scripting home

Understand c++11 Lambda expressions

Updated: August 12, 2020 09:29:31 by Dabelv
This article mainly introduces the relevant information of c++11 Lambda expression, to help you better understand and learn C++, interested friends can understand

1. Introduction

1.1 Definitions

C++11 adds a lot of features, Lambda expression is one of them, many languages provide Lambda expressions, such as Python, Java, C# and so on. Essentially, a Lambda expression is a callable unit of code [1]^{[1]}[1]. It is actually a closure, similar to an anonymous function, which has the ability to capture variables in its scope, and can be used as an object, usually to implement callback functions, proxies, and so on. Lambda expressions are the foundation of functional programming, and the introduction of Lambda in C++11 makes up for the gap in C++ functional programming.

1.2 Function

In the past, when C++ needed to pass a function, it had to be declared beforehand, either as a normal function and then passed in a function pointer, or as a functor (function object) and then passed in an object. For example, many algorithm function templates in C++ STL require predicate to be passed as a judgment condition, such as sorting algorithm sort. A predicate is a callable expression that returns a value that can be used as a condition. There are two types of predicates used by the library algorithms: unary predicates (which take a single argument) and binary predicates (which take two arguments). Algorithms that accept predicates invoke predicates on elements in the input sequence, so the element type must be able to be converted to the argument type of the predicate. The string is sorted from shorter to longer, as shown below, using sort() to pass in the comparison function shorter(), where the comparison function shorter() is the predicate.

// predicate: comparison function to sort the string by length bool shorter(const string& s1,const string& s2) {return s1.size()<s2.size(); } // words std::sort(words.begin(),words.end(),shorter); words STD ::sort(words.begin(),words.end(),shorter);

A Lambda expression can be used as a callable object, like a function pointer or a functor, for example as a predicate passed into a standard library algorithm.

One might ask, why introduce Lambda when you have function Pointers and function objects? Function objects can maintain state, but the syntax is expensive, and the function pointer syntax is small, but can not save the state in the function body. If you think you can't have your cake and eat it, you're wrong. Lambda functions combine the best of both worlds, allowing you to write elegant and concise code.

1.3 Syntax

A Lambda expression is just a callable unit of code that we can think of as an unnamed inline function. Like any function, a Lambda has a return type, a list of arguments, and a function body. But unlike functions, Lambda can be defined inside functions, with the following syntax:

[capture list](parameter list) mutable(optional) Exception attribute ->return type{function body}

The capture list is a list of local variables defined in the function in which the Lambda resides. It is usually empty, indicating that the Lambda does not use any local variables in the function in which it resides. The parameter list, return type, and function body are basically the same as any ordinary function, except that Lambda's argument list cannot have default arguments and must use a trailing return type. mutable means that a Lambda can modify captured variables; if mutable is omitted, it cannot. The exception attribute specifies the type of exception that a Lambda might throw.

The only required parts of the Lambda expression are the capture list and function body. When Lambda ignores the argument list, it specifies an empty argument list, and when it ignores the return type, Lambda can infer the return type from the code in the function body. For example:

auto f=[]{return 42; }

We define a callable object f that takes no arguments and returns 42. The auto keyword actually converts the Lambda expression to an internal type similar to std::function (but not std::function, though "compatible" with std::function). So, we can also write:

std::function<int()> Lambda = [] () -> int { return val * 100; };

If std::function<int()> sounds amazing to you, check out C++ 11 for std::function usage. In simple terms, std::function<int()> is an instantiated template class that represents a callable object that takes 0 arguments and returns an int. So, when we need an object that takes a double and returns int, we write: std::function<int(double)>[3]^{[3]}[3].

1.4 Call Mode

Lambda expressions are called in the same way as ordinary functions, and the above Lambda expressions are called as follows:

cout<<f()<<endl; // Print 42 // or call cout<<[]{return 42; }()<<endl;

We can also define a one-argument Lambda that implements the functionality of the shorter() comparison function for string sorting above:

auto f=[](cosnt string& a,const string& b) { return a.size()<b.size(); } // Pass Lambda into sort sort algorithm sort(words.begin(),word2.end(),[](cosnt string&a,const string&b){return a.ize ()< b.ize (); }); // or sort(words.begin(),word2.end(),f);

2.Lambda's capture list

A Lambda can get (capture) the value of a variable in its scope, and the capture list specifies the external variables that can be used within the code of a Lambda expression. For example, while a Lambda can appear in a function and use its local variables, it can only use those variables that are explicitly specified in the capture list. Lambda has two ways of capturing the required external variables: references and values. We can set the capture mode of each variable in the capture list. Without a capture list set, Lambda cannot capture any variables by default. There are several capture methods:

  • [] Do not intercept any variables
  • [&} intercepts all variables in the external scope and uses them as references in the body of the function
  • [=] Takes all variables in the external scope and makes a copy for use in the function body
  • [=,&valist] Takes all variables in the external scope and makes a copy for use in the function body, but uses a reference to valist separated by a comma
  • [&,valist] captures all variables in the external scope by reference, and valist uses values for a comma-separated list of variables
  • [valist] captures the value used by valist for a comma-separated list of variables
  • [&valist] captures the comma-separated variable list valist by reference
  • [this] intercepts the this pointer in the current class. This option is added by default if &or = is already used.

You can use variable a in Lambda by setting the capture list in [], where capture by value (=, by value) is used.

#include <iostream>

int main()
{
 int a = 123;
 auto lambda = [=]()->void
 {
 std::cout << "In Lambda: " << a << std::endl;
 };
 lambda();
 return 0;
}

The result of compiling and running is as follows:

In Lambda: 123

Variables passed to Lambda by value are immutable by default, and if you need to modify them in Lambda, you need to add the mutable keyword to the parameter list (passing by value does not change the value of variables outside Lambda).

#include <iostream>
int main()
{
 int a = 123;
 std::cout << a << std::endl;
 auto lambda = [=]() mutable ->void{
 a = 234;
 std::cout << "In Lambda: " << a << std::endl;
 };
 lambda();
 std::cout << a << std::endl;
 return 0;
}

The result of compiling is:

123 In Lambda: 234 // Can be modified 123 // Note that the value here does not change

If a mutable is not added, a compilation error occurs:

$ g++ main.cpp -std=c++11
main.cpp:9:5: error: cannot assign to a variable captured by copy in a non-mutable Lambda
    a = 234;
                ~ ^
1 error generated.

Seeing this, I can't help but ask, how is this magic variable capture achieved? Originally, Lambda was implemented by creating a class. This class overrides the operator (), and a Lambda function is an instance of this class. When the class is constructed, the surrounding variables are passed to the constructor and stored as member variables, similar to function objects (functors), but the C++11 standard recommends using Lambda expressions instead of function objects, which are more lightweight, efficient, and easy to use and understand. [4]^{[4]}[4]

3. Types of Lambda

The types of lambda functions look a lot like function Pointers, in that they assign a function to a variable. In fact, lambda functions are implemented using functors, which again look like a custom class. In fact, a lambda type is not a simple function pointer type or a custom type, a lambda function is a closure class, and the C++11 standard stipulates that closure types are unique, anonymous, and non-associative class types. Each lambda expression produces a temporary object (rvalue) of type closure. Therefore, strictly speaking, lambda functions are not function Pointers, but C++11 allows lambda expressions to be converted to function Pointers, provided that no variables are captured and the function pointer points to the same way the lambda function is called.

typedef int(*pfunc)(int x, int y); int main() { auto func = [](int x, int y)->int { return x + y; }; pfunc p1 = nullptr; p1 = func; //lambda expression to function pointer std::cout << p1(1, 2) << std::endl; return 0; }

4.lambda constants and mutable keywords

In C++11, lambda functions are const functions by default, and as a rule, a const member function cannot change the value of a non-static member variable within the function body.

int main() { int val = 0; auto const_val_lambda = [=] { val = 3; }; val auto mutable_val_lambda = [=]() mutable {val = 3; val auto mutable_val_lambda = [=]() Mutable {val = 3; }; auto const_ref_lambda = [&] { val = 3; }; auto const_param_lambda = [](int v) { v = 3; }; const_param_lambda(val); return 0; }

Reading the code, note the following: (1) You can see that variables captured by value cannot be modified in a const lambda function. lambda functions are implemented through functors, and the captured variables are equivalent to member variables in the functor class, while lambda functions are equivalent to member functions, and const member functions naturally cannot modify ordinary member variables. (2) A variable captured by reference will not cause an error if its value is changed in a constant member function, simply because const_ref_lambda will not change the reference itself, but only the value of the reference, so the compilation passes; (3) Use the mutable mutable_val_lambda to remove the const attribute, so you can modify variables captured by value; (4) const_param_lambda, which passes arguments by value, modifies the arguments passed to the lambda function, and of course there is no problem.

5. Common uses of Lambda

(1) Lambda functions and STL The introduction of Lambda functions provides great convenience for the use of STL. For example, when you wanted to traverse a vector, you would have to write:

vector<int> v={1,2,3,4,5,6,7,8,9}; // Traditional for loop for (auto itr = v.begin(), end = v.EGin (); itr ! = end; itr++ ) { cout << *itr; } // Function pointer void printFunc(int v) {cout<<v; } for_each(v.begin(),v.end(),printFunc); // struct CPrintFunc {void operator() (int val)const {cout << val; }}; for_each(v.begin(),v.end(),CPrintFunc());

Now with Lambda functions you can write:

for_each(v.begin(),v.end(),[](int val)
{ 
 cout << val;
});

Obviously, using lambda functions is much simpler than using traditional for loops, function Pointers, and functors. If the business code dealing with vector members is more complex, then the convenience of Lambda functions is more obvious. It is also more efficient to do so because the compiler may use loop expansion to speed up execution.

These are the details of this article to understand c++11 Lambda expressions. For more information about c++11 Lambda expressions, please pay attention to other related articles in Script House!

Related article

  • C++ 实现PE文件特征码识别的步骤

    C++ implementation of PE file feature code recognition steps

    PE file is the EXE executable file we often say, for the identification of file characteristics can clearly know what kind of programming language is used to achieve the program, the premise is to have a feature library, PE feature recognition has a variety of forms, the first is static identification, the second is dynamic identification, we often use PEID shell tool is based on static detection method.
    2021-06-06
  • QT实现多线程两种方式案例详解

    QT implementation of multithreading two ways of case details

    This article mainly introduces the QT multi-threaded two ways of case details, this article through a brief case, explained the understanding and use of the technology, the following is the details, the need of friends can refer to
    2021-08-08
  • 详解C语言如何计算结构体大小(结构体的内存对齐)

    Detail how C calculates struct size (memory alignment of structs)

    Structure memory alignment is a very important knowledge point about the structure content, the main way to study is to calculate the byte size of the structure, so this article will give you a detailed introduction to the C language how to calculate the size of the structure, the code example in the article is very detailed, the need of friends can refer to the next
    2023-07-07
  • rapidjson解析json代码实例以及常见的json core dump问题

    rapidjson parses json code instances and common json core dump problems

    Today, Xiaobian will share an article about rapidjson parsing json code examples and common json core dump problems for you. Xiaobian feels that the content is very good, and now it is shared with you, which has a good reference value. Friends need to follow Xiaobian to see
    2019-04-04
  • 深入分析C语言中结构体指针的定义与引用详解

    In-depth analysis of the definition and reference of structure pointer in C language

    This article is a detailed analysis of the definition and reference of structure Pointers in the C language, and needs a friend's reference
    2013-05-05
  • C语言求字符串长度的四种方法实例代码

    C language to find the length of the string of four methods example code

    In the application process of C language will often use the string, as well as the length of the string to calculate the problem, the following article mainly introduces you about the C language to obtain the length of the string of four methods of the relevant information, the need of friends can refer to the next
    2022-12-12
  • c++ 端口扫描程序实现案例

    c++ port scanner implementation case

    The following Xiaobian will bring you a c++ port scanner implementation case. Xiaobian feel very good, now to share with you, but also to give you a reference. Let's take a look
    2017-05-05
  • C语言函数的基本使用和递归小结

    Basic use and recursive summary of C language functions

    This article mainly introduces the basic use of C language functions and recursive summary, this article gives you a very detailed introduction, for everyone's study or work has a certain reference value, the need of friends can refer to
    2021-09-09
  • C++面试八股文之了解auto关键字

    C++ interview eight articles to understand the auto keyword

    This article mainly introduces the C++ interview eight parts to understand the auto keyword problem analysis, the need of friends can use for reference, I hope to be helpful, I wish you a lot of progress, early promotion and pay rise
    2023-06-06
  • 使用C语言实现CRC校验的方法

    The method of CRC verification using C language

    This article is the use of C language to achieve CRC verification method for a detailed analysis of the introduction, the need for friends reference
    2013-05-05

Latest comments