C ++ Lambda compiler implementation principle

Lambda expression syntax

Complete format Lambda expressions are as follows:

[捕获列表] (形参列表) mutable 异常列表-> 返回类型
{
    函数体
}

Various meanings:

  1. Capture List : Variable capture external variable, the function may be used to capture the body may be omitted, i.e. not trapped external variables.
  2. Parameter list : parameter list and normal function of the same. It may be omitted, i.e. no parameter list
  3. the mutable : the mutable keyword, if there is, then you can modify captured variables in the function body, decide whether to omit specific needs.
  4. List of exceptions : noexcept / throw (...), and a list of exceptions, like ordinary functions, can be omitted, that representative may throw any type of exception.
  5. Return Type : return type and function of the same. It may be omitted, and if omitted, the compiler will automatically return type is derived.
  6. Function body : code. It can be omitted, but meaningless.

Examples of Use

void LambdaDemo()
{
    int a = 1;
    int b = 2;
    auto lambda = [a, b](int x, int y)mutable throw() -> bool
    {
        return a + b > x + y;
    };
    bool ret = lambda(3, 4);
}

Compiler implementation principle

Compiler implements lambda expression is broadly divided into what steps

  1. Create a lambda class , implement the constructor, using the weight load of the lambda expression function operator () (also called a lambda expression so anonymous function object)
  2. Create a lambda objects
  3. Call through the object operator ()

The compiler will lambda expressions translated code:

class lambda_xxxx
{
private:
    int a;
    int b;
public:
    lambda_xxxx(int _a, int _b) :a(_a), b(_b)
    {
    }
    bool operator()(int x, int y) throw()
    {
        return a + b > x + y;
    }
};
void LambdaDemo()
{
    int a = 1;
    int b = 2;
    lambda_xxxx lambda = lambda_xxxx(a, b);
    bool ret = lambda.operator()(3, 4);
}

Among them, the class name lambda_xxxx of xxxx is to prevent naming conflicts plus the.

Correspondence between lambda_xxxx and lambda expressions

  1. lambda expressions capture list , the corresponding lambda_xxxx class private members
  2. lambda expression parameter lists corresponding lambda_xxxx class member function operator () in parameter list
  3. lambda expression of the mutable , lambda_xxxx class member function corresponding to operator () const constant properties , i.e., whether it is often member functions
  4. lambda expression return type , the corresponding lambda_xxxx class member function operator () return type
  5. lambda expression function body , corresponding to lambda_xxxx class member function operator () member function

Further, lambda expression captured, the capture list, also impact the type corresponding to the private members of class lambda_xxxx

  1. Value capture: the same type of private member variable of the type of capture
  2. Capture reference: type of private member variables of a reference type is captured

Do not capture any external variables

If the lambda expression does not capture any external variables, under certain circumstances, there will be additional code generation.
Wherein the specific case means: there lambda_xxxx class to function pointer type conversion
such as the following code

typedef int(_stdcall *Func)(int);
int Test(Func func)
{
	return func(1);
}
void LambdaDemo()
{
	Test([](int i) {
		return i;
	});
}

Test function takes a function pointer as an argument, and calls the function pointer.

Test When actual call, it is a parameter passed Lambda expressions, so there is a kind of implicit conversion
lambda_xxxx => pointer to a function.

As already mentioned, Lambda expression is normally should not exist to convert between a lambda_xxxx anonymous object class, a function pointer, but the above code has no problem.

The key is their problem, the above code, lambda expression does not capture any external variables, namely lambda_xxxx class has no member variables, the operator () will not be used in any member variables, that is to say, operator () Although it is a member function, it can not rely on this call.

Because they do not rely on this, so there may be a transition between a function pointer anonymous lambda_xxxx object class.

Substantially as follows:

  1. In lambda_xxxx generate a class static function , a function of the static function signature and operator () consistent with , in this static function by a null pointer to the class of the calling operator ()
    2. Overload lambda_xxxx type conversion function pointers operator, in this function, the first step in the return address static functions.

The code following code after translation compiler:

typedef int(_stdcall *Func)(int);

class lambda_xxxx 
{
private:
	//没有捕获任何外部变量,所有没有成员
public:
        /*...省略其他代码...*/
	int operator()(int i)
	{
		return i;
	}
	static int _stdcall lambda_invoker_stdcall(int i)
	{
		return ((lambda_xxxx *)nullptr)->operator()(i);
	}

	operator Func() const
	{
		return &lambda_invoker_stdcall;
	}
};

int Test(Func func)
{
	return func(1);
}
void LambdaDemo()
{
	auto lambda = lambda_xxxx ();
	Func func = lambda.operator Func();
	Test(func);
}

In the above code simply __stdcall calling convention function pointer example, actual use different calling conventions, will generate the corresponding version of the static type conversion functions and function

These conclusions correctness by an explicit call to demonstrate conversion function and disassembly of lambda

void LambdaDemo()
{
	auto lambda = [](int i) {return i;};
	Func func = lambda.operator Func();
	Test(func);
}
  • Converted to function pointers

1png

738 x 691221 x 114

  • The static function lambda_invoker_stdcall address conversion function as a type of return value

2png

  • Static function lambda_invoker_stdcall using 0 as this call operator ()

3png

Guess you like

Origin www.cnblogs.com/cute/p/12455769.html
Recommended