C++11_lambda expression, wrapper, bind binding

1.lambda expression

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

mutable: by default, lambda expressions have const attribute by default. mutable can cancel its const attribute. Note: when using this modifier, the parameter list cannot be omitted even if it is empty

When there is no mutable in the parameter list, if it is empty, it can be omitted, and the return value type can also be omitted

[]: capture list. At the beginning of lambda expression, the compiler can capture context variables for lambda expression to reduce parameters

Capture list description

The capture list describes which data in the context can be used by lambda, and whether it is passed by value or reference.
[var]: indicates the value transfer method and captures the variable var
[= =: indicates that the value transfer method captures all variables in the parent scope (this is included in the member function)
[& var]: refers to the reference transfer capture variable var
[&]: indicates that reference passing captures all variables in the parent scope (including this)
be careful:
a. The parent scope refers to the statement block containing the lambda function
b. Syntactically, the capture list can be composed of multiple capture items and separated by commas
eg:

  1. [=, & a, & b]: capture variables a and b by reference transfer, and all other variables by value transfer
  2. [&, a, this]: capture variables A and this in value transfer mode and other variables in reference mode

c. The capture list does not allow variables to be passed repeatedly, otherwise it will lead to compilation errors.
eg:

[=, a]: = all variables have been captured by value transfer, and a is repeated

d. The lambda function capture list outside the scope of the block must be empty

e. lambda expressions cannot be assigned to each other

Eg: lambda expression of C + + swap function

#include<iostream>

using std::cout; using std::endl;

int main()
{
	int a = 10; int b = 20;
	auto swap = [](int& x, int& y)->void {int tmp = x; x = y; y = tmp; };
	//Use snap list
	auto swap1 = [&a, &b] {int tmp = a; a = b; b = tmp; };//mutable cancels the constancy of lambda expressions
	auto swap2 = [&] {int tmp = a; a = b; b = tmp; };//Reference full snap
	return 0;
}

C++11 lambda principle

The lambda expression is converted into an imitation function by the compiler, and the name of the class is lambda+uuid string
eg:

The parameters captured or passed by the operator () calling the functor will be passed to the functor in the form of parameters

Therefore, lambda expressions cannot be assigned to each other because the type names of the two lambda expressions are different

2. Packer

C + + callable object types are:
Function pointer, imitation function, lambda expression

#include<iostream>

using std::cout; using std::endl;

template<class F,class T>
T usF(F f, T t)
{
	static int a = 0;
	cout << a << endl;
	a++;
	cout << &a << endl;
	return f(a);
}

double fun(double num)
{
	return num / 2;
}

struct Functer
{
	double operator()(double Num)
	{
		return Num / 2;
	}
};

int main()
{
	//Function pointer
	cout << usF(fun, 15.6) << endl;
	//functor 
	cout << usF(Functer(), 12.4) << endl;
	//lambda expressions 
	cout << usF([](double Num)->double {return Num / 2; }, 12.4) << endl;
	return 0;
}

Analyze the above Codes:
The above function template will be instantiated three times.

In order to reduce the number of instantiated objects, the wrapper is introduced. Encapsulate all the above callable objects and call them in a unified way.

#include<iostream>
#include<functional>

using std::cout; using std::endl;

template<class F,class T>
T usF(F f, T t)
{
	static int a = 0;
	cout << a << endl;
	a++;
	cout << &a << endl;
	return f(a);
}

double fun(double num)
{
	return num / 2;
}

struct Functer
{
	double operator()(double Num)
	{
		return Num / 2;
	}
};

struct Functer1
{
	static double Print(double x)
	{
		cout << "Static" << endl;
		return x / 2;
	}
	double Print2(double x)
	{
		return x / 2;
	}
};

int main()
{

	//Wrapper function pointer
	std::function<double(double)>ff = fun;//STD:: function < double (double) > FF indicates that the parameter is double and the return value is double
	//Packing imitation function
	std::function<double(double)>ff1 = Functer();
	//Wrapping static member functions
	std::function<double(double)>ff2 = Functer1::Print;
	// Wrapping non static member functions
	std::function<double(Functer1, double)>ff3 = &Functer1::Print2;//this pointer 
	cout << ff3(Functer1(), 12.3) << endl;//An object is required for calling
	//Wrapping lambda expressions
	auto tmp = [](double num)->double {return num / 2; };
	std::function<double(double)>ff4 = tmp;
	cout << usF(ff, 12.4) << endl;
	cout << usF(ff1, 12.4) << endl;
	cout << usF(ff2, 12.4) << endl;
	cout << usF(ff4, 12.4) << endl;

	return 0;
}

According to the above code, if the parameter and return value types are the same, no matter which callable type can be represented by the same wrapper. In this way, the number of instantiations can be reduced when passing to the template function

bind binding

std::band function is a general function adapter in the functional header file. It accepts an object and generates a new callable object to adapt to the parameter list of the original object

#include<iostream>
#include<functional>

using std::cout; using std::endl;

struct Sub
{
	int sub(int a, int b)
	{
		return a - b;
	}
};

int Add(int a, int b)
{
	return a + b;
}

int main()
{
	//Bind the Add function to parameter + 10
	std::function<int(int)>ff = std::bind(Add, std::placeholders::_1, 10/*std::placeholders::_2*/);//Accept two parameters. The first parameter is_ 1. The second parameter is_ two
	cout << ff(12) << endl;

	//A non static member function call requires an object, which is bound to a parameter passing object
	std::function<int(int, int)>ff1 = std::bind(&Sub::sub, Sub(), std::placeholders::_1, std::placeholders::_2);
	cout << ff1(12, 10) << endl;
	return 0;
}


You can also control the order of parameter transfer by adjusting STD:: placeholders:_ 1, std::placeholders::_ 2 order is enough

Keywords: C++ Back-end

Added by slyte33 on Sun, 13 Feb 2022 07:54:48 +0200