Functions, bind, and Lambda in C ++

Source: Internet
Author: User

This is the fourth article in the C ++ 0x series. It mainly covers the newly added lambda expressions, function objects, and bind mechanisms in C ++ 0x. The reason for putting these three parts together is that they are closely related. Through comparative learning, we can deepen our understanding of this part of content. At the beginning, we should first talk about a concept, closure (closure), which is the basis for understanding lambda. Let's take a look at the definition of closure in the computer field on Wikipedia:

A closure (also lexical closure, function closure or function value) is a function together witha referencing environment for the non-local variables of that function.

The preceding definition indicates that closure is a set of functions and the context environment of the non-local variables referenced by closure. From the definition, we can know that closure can access variables out of its definition scope, that is, the non-local vriables mentioned above, which greatly increases its skill. The most important application of closure is the callback function, which is also the main reason why function, bind, and Lambda are put together. The three of them are different in the process of using the callback function. The secrets of the three are given step by step.

  • 1. Function

    We know that in C ++, callable entities mainly include functions, function pointers, and function references. They can be implicitly converted to the objects specified by the function, or opetator () is implemented () (C ++ 98 functor ). In C ++ 0x, a new STD: function object, STD :: A function object is a type-safe package for the existing callable entities in C ++ (we know that callable entities such as function pointers are of Type insecurity ). Let's look at several examples of function objects:

    #include < functional> std::function< size_t(const char*)> print_func; /// normal function -> std::function objectsize_t CPrint(const char*) { ... }print_func = CPrint;print_func("hello world"): /// functor -> std::function objectclass CxxPrint{public:    size_t operator()(const char*) { ... }};CxxPrint p;print_func = p;print_func("hello world");

    In the above example, we assign a common function and a functor to a STD: function object, and then call it through this object. Other callable entities in C ++ can be used as above. With the STD: function package, we can pass callable entities like passing common objects, which effectively solves the type security problem. After learning about the basic usage of STD: function, let's take a look at some precautions during usage:

    • (1) The following two principles must be observed for converting callable entities to STD: Function objects:
      A. The parameters of the converted STD: function object can be converted to parameters of callable entities.
      B. the returned values of highly usable entities can be converted to STD: Function objects (note that the returned values of all callable entities are the same as those of the STD :: function object return value Compatibility ).
    • (2) STD: The function object can be refer to any callable entity that meets the conditions in (1 ).
    • (3) STD: function object is most useful in implementing function callback. You must note that it cannot be used to check whether it is equal or not.
  • 2. Bind

    BIND is a mechanism that can pre-bind certain parameters of a specified callable object to an existing variable to generate a new callable object, this mechanism is also useful in the use of callback functions. In C ++ 98, there are two functions bind1st and bind2nd, which can be used to bind the first and second parameters of functor, both of which can be bound with only one parameter. Various restrictions greatly reduce the availability of bind1st and bind2nd. In C ++ 0x, STD: BIND is provided. The number of parameters bound to the STD: BIND is not limited, and the specific parameters bound are not limited, this BIND is the binding in the real sense. With it, bind1st and bind2nd are useless. Therefore, bind1st and bind2nd are not recommended in C ++ 0x. They are all deprecated. The following example shows the usage of BIND:

    #include < functional> int Func(int x, int y);auto bf1 = std::bind(Func, 10, std::placeholders::_1);bf1(20); ///< same as Func(10, 20) class A{public:    int Func(int x, int y);}; A a;auto bf2 = std::bind(&A::Func, a, std::placeholders::_1, std::placeholders::_2);bf2(10, 20); ///< same as a.Func(10, 20) std::function< int(int)> bf3 = std::bind(&A::Func, a, std::placeholders::_1, 100);bf3(10); ///< same as a.Func(10, 100)

    In the above example, bf1 binds the first parameter of two common functions to 10 and generates a new parameter called Object Body; bf2 binds a class member function to a Class Object and generates a new callable object like a common function; bf3 binds the class member function to the class object and the second parameter to generate a new STD: function object. After reading the above example, we will discuss some precautions for using bind:

    • (1) bind pre-bound parameters need to be passed in with specific variables or values. For pre-bound parameters, it is pass-by-Value
    • (2) For parameters not pre-bound, STD: placeholders must be passed in, starting from _ 1 and increasing sequentially. Placeholder is from pass-by-reference.
    • (3) the return value of BIND is a callable entity, which can be directly assigned to the STD: function object.
    • (4) For the bound pointer and reference type parameters, you must ensure that these parameters are available before calling the object.
    • (5) This of a class can be bound by an object or pointer.
  • 3. Lambda

    After talking about functions and bind, let's look at Lambda. Those who have Python basics are confident that Lambda will not be unfamiliar. If you see a friend here, remember the concept of closure mentioned above. Lambda is used to implement closure. Its maximum use is also in the callback function, which is closely related to the previously mentioned function and bind. Let's take an example to see the true colors of Lambda:

    vector< int> vec;/// 1. simple lambdaauto it = std::find_if(vec.begin(), vec.end(), [](int i) { return i > 50; });class A{public:    bool operator(int i) const { return i > 50; }};auto it = std::find_if(vec.begin(), vec.end(), A()); /// 2. lambda return syntaxstd::function< int(int)> square = [](int i) -> int { return i * i; } /// 3. lambda expr: capture of local variable{    int min_val = 10;    int max_val = 1000;     auto it = std::find_if(vec.begin(), vec.end(), [=](int i) {        return i > min_val && i < max_val;         });     auto it = std::find_if(vec.begin(), vec.end(), [&](int i) {        return i > min_val && i < max_val;        });     auto it = std::find_if(vec.begin(), vec.end(), [=, &max_value](int i) {        return i > min_val && i < max_val;        });} /// 4. lambda expr: capture of class memberclass A{public:    void DoSomething(); private:    std::vector<int>  m_vec;    int               m_min_val;    int               m_max_va;}; /// 4.1 capture member by thisvoid A::DoSomething(){    auto it = std::find_if(m_vec.begin(), m_vec.end(), [this](int i){        return i > m_min_val && i < m_max_val; });} /// 4.2 capture member by default pass-by-valuevoid A::DoSomething(){    auto it = std::find_if(m_vec.begin(), m_vec.end(), [=](int i){        return i > m_min_val && i < m_max_val; });} /// 4.3 capture member by default pass-by-referencevoid A::DoSomething(){    auto it = std::find_if(m_vec.begin(), m_vec.end(), [&](int i){        return i > m_min_val && i < m_max_val; });}

    The above example basically covers the basic usage of lambda expressions. Let's analyze each example one by one (the label is consistent with the 1, 2, 3, 4 in the above Code comment ):

    • (1) This is the simplest Lambda expression. It can be considered that the find_if with the lambda expression is equivalent to the find_if with the functor below.
    • (2) This is a Lambda expression with a returned value. The syntax of the returned value is shown above. It is written after the brackets in the parameter list through->. The returned values can be omitted in the following cases:
      A. When the return value is void
      B. There is return expr in the body of the lambda expression, and the expr type is the same as the return value.
    • (3) This is an example of the lambda expression capture local variable. Here, three small examples are different syntaxes for capture, in the first small example, = indicates the capture variable pass-by-value. In the second small example, & indicates the capture variable pass-by-reference, in the third small example, the default pass-by-value is specified, but max_value is a separate pass-by-reference.
    • (4) This is an example of a member variable of the lambda expression capture class. There are also three small examples. The first small example uses the this pointer to capture member variables. The second and third are by default, but the second is by pass-by-value, the third is through pass-by-Reference

    After analyzing the above example, we will summarize some precautions for using lambda expressions:

    • (1) to use a referenced variable in a Lambda expression, follow the following principles:
      A. The local variable in the call context can be referenced only when the capture is used (as shown in Example 3 above)
      B. Non-local variables can be directly referenced.
    • (2) Users should note that closure (the callable entity generated by lambda expressions) must ensure that the variables referenced (mainly pointers and references) are available before closure is called, this is consistent with the callable object generated after the BIND parameter is bound.
    • (3) Lambda is used to generate closure, while closure is also a callable entity. Therefore, you can use the STD: function object to save the generated closure, you can also directly use auto

    Through the above introduction, we have a basic understanding of functions, bind and Lambda usage, and combined them, C ++ will become very powerful and a little Functional Programming taste. Finally, I would like to add that for function generation using bind and function generation using lambda expressions, both of them are usually OK, but when there are many parameters, bind requires a lot of STD: placeholders, And it looks intuitive without lambda expressions, So we generally recommend that you use lambda expressions first.

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.