Summary of lambda anonymous, using and typedef in C++ [Full] (249)

Introduction: CSDN blog expert, focusing on Android/Linux System, share multi-mic voice solutions, audio and video, codec and other technologies, and grow with everyone!

Quality Column:Audio Engineer Advanced Series[Original information is being updated continuously… ]

Life motto: There are never shortcuts in life, only actions It is the only cure for fear and laziness.


For more original works, welcome to follow: Android System Siege Lion

Welcome to follow Android System Siege Lion

1. Preface

The purpose of this article: Understand the usage of lambda anonymous functions, typedef, using, etc. in C++

2. Introduction to lambda anonymous, using and typedef in C++

1.lambda introduction

  • Lambda function is an anonymous function that can be used in C++. It provides a concise way to define and use temporary function objects. Lambda functions simplify the creation process of function objects by using convenient syntax, making the code more concise and readable.

The basic syntax of a Lambda function is as follows:

[capture list] (parameters) -> return_type { function_body }
  • Capture list: Specify the external variables captured by the Lambda function. It can be value capture (copy by value) or reference capture (access by reference).
  • Parameter list: Specify the parameters of the Lambda function.
  • Return type: Specify the return type of the Lambda function (can be omitted, the compiler will automatically infer it).
  • Function body: implements the specific logic of the Lambda function.

3.Lambda anonymous, using, typedef introduction

  1. Lambda anonymous function:
    A Lambda function is an anonymous function that allows us to define temporary, immediate function logic where a function object is required. Its syntax is as follows:
[capture list] (parameters) -> return_type { function_body }
  • Capture list (optional): Specifies the external variables captured by the Lambda function.
  • Parameter list: Specify the parameters of the Lambda function.
  • Return type (optional): Specify the return type of the Lambda function. If not specified, the compiler will automatically infer it.
  • Function body: implements the specific logic of the Lambda function.

Lambda functions can be used in algorithm functions, STL container processing, callback functions, etc., making the code more concise and readable.

  1. using statement:
    The Using statement is used in C++ to introduce a specific type or namespace for use in the current scope. Its syntax is as follows:
using name = type;

Here name is the alias we defined, and type is the type that needs to be introduced.

Using declarations can be used to simplify complex type names or to introduce types in a namespace. For example:

using IntVector = std::vector<int>;

IntVector numbers = {<!-- -->1, 2, 3, 4, 5};

Here, we use the using declaration to introduce the std::vector type alias IntVector, thus simplifying it into a more readable name.

  1. typedef declaration:
    Typedef declarations are also used to introduce a specific type alias for use in the current scope. Its syntax is as follows:
typedef type name;

Here type is the type we need to introduce, and name is the alias we defined.

Typedef declarations are similar to using declarations in that they can also be used to simplify complex type names. For example:

typedef std::vector<int> IntVector;

IntVector numbers = {<!-- -->1, 2, 3, 4, 5};

Here, we use a typedef declaration to define the std::vector type as IntVector, making the code more readable.

Summarize:
Lambda functions provide a concise way to define anonymous functions, using declarations and typedef declarations provide the ability to simplify type names. These tools can make code clearer, more readable, and easier to maintain.

3. Code examples

v1.0 function call example

#include <iostream>
#include <string>
#include <functional>

typedef std::function<int(int x, int y)> Callback;
using UCallback = std::function<int(int x, int y)>;

//v1.0
int call_add(std::function<int(int x, int y)> call){<!-- -->
  int a = 100, b=500;
  call(a, b);//Pass the values a and b to the caller.
  return a + b;
}

//v2.0: Same as above: use typedef to define Callback type alias definition
int call_add_01(Callback call){<!-- -->
  int a = 100, b=500;
  call(a, b);//Pass the values a and b to the caller.
  return a + b;
}

//v3.0: Same as above: use using to define UCallback type alias definition
int call_add_02(UCallback call){<!-- -->
  int a = 100, b=500;
  call(a, b);//Pass the values a and b to the caller.
  return a + b;
}

int main() {<!-- -->
  //v1.0: Anonymous lambda function, no parameters, no return value.
  [](){<!-- -->
    printf("xxx----->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }();

  //v2.0: Anonymous lambda function, with string parameters and no return value.
  [](std::string content){<!-- -->
    printf("xxx----->%s(), line = %d, content = %s\
",__FUNCTION__,__LINE__,content.c_str());
  }("Hello Wolrd.");

  //v3.0: Anonymous lambda function, with string and int type parameters, no return value.
  std::string buf = "Hello, C++ !";
  int year = 2023;
  [](std::string buf, int years){<!-- -->
    printf("xxx----->%s(), line = %d, buf = %s, years = %d\
",__FUNCTION__,__LINE__,buf.c_str(), years);
    
  }(buf, year);

  //v3.1: lambda with return value
  int moth = [](std::string buf, int years){<!-- -->
    printf("xxx----->%s(), line = %d, buf = %s, years = %d\
",__FUNCTION__,__LINE__,buf.c_str(), years);
    int month = 10;
    return month;
  }(buf, year);
  printf("xxx----->%s(), line = %d, moth = %d\
",__FUNCTION__,__LINE__,moth);
  

  //4.0: Use typedef to create an alias type Callback, and then call the callback function.
  Callback add = [](int a, int b)->int {<!-- -->
    printf("xxx---------->%s(), line = %d, a = %d, b = %d\
",__FUNCTION__,__LINE__,a,b);
    return a + b;
  };
  printf("xxx----->%s(), line = %d, add = %d\
",__FUNCTION__,__LINE__,add(2, 3));

  //v5.0: Use typedef to define callback function type aliases
  int ret1 = call_add(add);
  printf("xxx----->%s(), line = %d, ret1 = %d\
",__FUNCTION__,__LINE__,ret1);

  //v6.0: Use lambda anonymous callback function directly
  int ret2 = call_add([](int x, int y)->int{<!-- -->
    return x + y;
  });
  printf("xxx----->%s(), line = %d, ret2 = %d\
",__FUNCTION__,__LINE__,ret2);

  //v7.0: Use typedef to define callback function type aliases
  int ret3 = call_add_01(add);
  printf("xxx----->%s(), line = %d, ret3 = %d\
",__FUNCTION__,__LINE__,ret3);

  //v8.0: Use using to define callback function type aliases
  int ret4 = call_add_02(add);
  printf("xxx----->%s(), line = %d, ret4 = %d\
",__FUNCTION__,__LINE__,ret4);

  //v9.0: Use lambda anonymous callback function directly
  int ret5 = call_add_02([](int x, int y)->int{<!-- -->
    return x + y;
  });
  printf("xxx----->%s(), line = %d, ret5 = %d\
",__FUNCTION__,__LINE__,ret5);

  return 0;
}


v2.0 Class pointer, reference, pointer reference instance 01

#include <iostream>
#include <string>
#include <memory>
#include <functional>

class TEST{<!-- -->
public:
  void log(){<!-- -->
    printf("xxx--------->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }

  TEST(){<!-- -->
    printf("xxx--------->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }

  TEST(std::shared_ptr<TEST> & amp;test){<!-- -->
    printf("xxx--------->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }
};

//1.typedef definition: typedef type alias.
typedef std::function<void(std::shared_ptr<TEST> & amp;test)> Callback ;
//2.using definition: using alias = type.
using UCallback = std::function<void(std::shared_ptr<TEST> & amp;test)> ;

void callback_test(std::function<void(std::shared_ptr<TEST> & amp;test)> func){<!-- -->
  std::shared_ptr<TEST> tt = std::make_shared<TEST>();
  func(tt);
}


int main() {<!-- -->
  //v1.0: lambda anonymous function returns pointer TEST* type, no parameters
  TEST *t1 = [ & amp;]()->TEST*{<!-- -->
    return new TEST;
  }();
  t1->log();

  //v1.1
  TEST *t12 = [ & amp;]()->TEST*{<!-- -->
    return new TEST;
  }();
  t12->log();

  //2.0: lambda anonymous function returns TEST type pointer object, no parameters
  TEST t2 = [ & amp;]()->TEST{<!-- -->
    return TEST{<!-- -->}; //TEST{} way to create objects
  }();
  t2.log();

  //v2.1: TEST() object creation method
  TEST t21 = [ & amp;]()->TEST{<!-- -->
    return TEST();
  }();
  t21.log();

  //3.0: lambda anonymous function returns TEST type pointer object, no return value
  TEST *t3;
  [ & amp;](TEST *tr){<!-- -->
    tr = new TEST;
  }(t3);
  t3->log();

  //4.0: lambda anonymous function returns a reference object of TEST type pointer, no return value
  TEST *t4;
  [ & amp;](TEST* & amp;tr){<!-- -->//Reference of pointer
    tr = new TEST();
  }(t4);
  t4->log();

  //5.0: lambda anonymous function returns TEST type shared_ptr pointer object, no return value
  std::shared_ptr<TEST> t5;
  [ & amp;](std::shared_ptr<TEST> tr){<!-- -->//Pointer to TEST type shared_ptr pointer object
    tr = std::make_shared<TEST>();
  }(t5);
  t5->log();

  //6.0: lambda anonymous function returns a reference object of TEST type shared_ptr pointer, no return value
  std::shared_ptr<TEST> t6;
  [ & amp;](std::shared_ptr<TEST> & amp;tr){<!-- -->//The object pointing to the reference of the TEST type shared_ptr pointer, that is, the alias of the make_shared<TEST>() pointer object.
    tr = std::make_shared<TEST>();
  }(t6);
  t6->log();

  //7.0: lambda anonymous function returns a reference object of TEST type shared_ptr pointer
  std::shared_ptr<TEST> t7;
  [ & amp;](std::shared_ptr<TEST> & amp;tr)->std::shared_ptr<TEST> {<!-- -->//The object pointing to the reference of the TEST type shared_ptr pointer, that is, make_shared< TEST>() Alias of pointer object.
    //tr = std::make_shared<TEST>();
    return std::make_shared<TEST>(tr);
  }(t7);
  t7->log();

  //8.0: lambda anonymous function returns a reference object of TEST type shared_ptr pointer, with return value and parameters.
  /*The difference between t8 and t8.get():
    t8 is a shared pointer of type std::shared_ptr<TEST>, pointing to a TEST object.
    t8.get(): returns a raw pointer pointing to the same object.
  */
  std::shared_ptr<TEST> t8;
  [ & amp;](void* tr) -> std::shared_ptr<TEST> {<!-- -->
    return std::make_shared<TEST>(static_cast<TEST*>(tr));
  }(t8.get());
  t8->log();

  //9.0
  std::shared_ptr<TEST> t10;
  callback_test([ & amp;](std::shared_ptr<TEST> & amp; tr) -> void {<!-- -->
    t10 = tr;
  });
  t10->log();

  return 0;
}


v3.0 Class pointer, reference, pointer reference instance 02

#include <iostream>
#include <string>
#include <memory>
#include <functional>

class TEST{<!-- -->
public:
  void log(){<!-- -->
    printf("xxx--------->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }

  TEST(){<!-- -->
    printf("xxx--------->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }

  TEST(std::shared_ptr<TEST> & amp;test){<!-- -->
    printf("xxx--------->%s(), line = %d\
",__FUNCTION__,__LINE__);
  }
};

//1.typedef definition: typedef type alias.
typedef std::function<void(std::shared_ptr<TEST> & amp;test)> Callback ;
//2.using definition: using alias = type.
using UCallback = std::function<void(std::shared_ptr<TEST> & amp;test)> ;

void callback_test(std::function<void(std::shared_ptr<TEST> & amp;test)> func){<!-- -->
  std::shared_ptr<TEST> tt = std::make_shared<TEST>();
  func(tt);
}

std::shared_ptr<TEST> callback_ret(){<!-- -->
  //std::shared_ptr<TEST> tt = std::make_shared<TEST>();
  //return tt;
  return std::make_shared<TEST>();
}

int main() {<!-- -->
  //v1.0
  std::shared_ptr<TEST> t1= callback_ret();
  t1->log();

  //v2.0
  std::shared_ptr<TEST> t2;
  callback_test([ & amp;](std::shared_ptr<TEST> & amp;tr) -> void {<!-- -->
    t2 = tr;
  });
  t2->log();

  return 0;
}

Implementation of shared_ptr and shared_ptr::get() in C++

template<typename T>
class shared_ptr {<!-- -->
public:
    explicit shared_ptr(T* ptr = nullptr) : ptr_(ptr), ref_count_(new int(1)) {<!-- -->}

    ~shared_ptr() {<!-- -->
        if (--(*ref_count_) == 0) {<!-- -->
            delete ptr_;
            delete ref_count_;
        }
    }

    shared_ptr(const shared_ptr & amp; other) : ptr_(other.ptr_), ref_count_(other.ref_count_) {<!-- -->
         + + (*ref_count_);
    }

    shared_ptr & amp; operator=(const shared_ptr & amp; other) {<!-- -->
        if (this != & amp;other) {<!-- -->
            if (--(*ref_count_) == 0) {<!-- -->
                delete ptr_;
                delete ref_count_;
            }
            ptr_ = other.ptr_;
            ref_count_ = other.ref_count_;
             + + (*ref_count_);
        }
        return *this;
    }

    T* get() const {<!-- -->
        return ptr_;
    }

private:
    T* ptr_; // Raw pointer to the managed object
    int* ref_count_; // Reference count, records the number of smart pointers sharing this object
};

The shared_ptr class maintains a pointer ptr_ and a counter ref_count_. Whenever there is a new shared_ptr pointing to the same object, ref_count_ is incremented. When no shared_ptr points to the object, ref_count_ is decremented and the resource is released when it reaches zero.

The implementation of the get() function is very simple. It only needs to return the private member ptr_, which is the original pointer of the object being managed.