principio de la ejecución del compilador C ++ Lambda

sintaxis de las expresiones lambda

de formato completo expresiones lambda son los siguientes:

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

Varios significados:

  1. Lista de captura : captura variable variable externa, la función puede ser usado para capturar el cuerpo puede omitirse, es decir, no atrapado variables externas.
  2. Lista de parámetros : lista de parámetros y la función normal de la misma. Se puede omitir, es decir, no lista de parámetros
  3. lo mutable : la palabra clave mutable, si la hay, entonces usted puede modificar las variables capturadas en el cuerpo de la función, decidir si las necesidades específicas Omitir.
  4. Lista de excepciones : noexcept / tiro (...), y una lista de excepciones, como las funciones ordinarias, se puede omitir, que el representante puede lanzar cualquier tipo de excepción.
  5. Tipo de retorno : tipo de retorno y la función de la misma. Se puede omitirse, y si se omite, será automáticamente el tipo de retorno se deriva el compilador.
  6. cuerpo de la función : código. Puede omitirse, pero sin sentido.

Ejemplos de Uso

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);
}

principio de la ejecución del compilador

Compilador implementa expresión lambda se divide a grandes rasgos en qué medidas

  1. Crear una clase lambda , implementar el constructor, utilizando el peso de la carga de la función de expresión lambda operador () (también llamada una expresión lambda de manera anónima objeto de función)
  2. Crear una lambda objetos
  3. Llame a través del objeto de operador ()

El código de expresiones lambda compilador traducida:

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);
}

Entre ellos, el nombre de la clase lambda_xxxx de xxxx es para evitar conflictos de nombres más el.

La correspondencia entre lambda_xxxx y lambda expresiones

  1. lambda expresiones lista de captura , las correspondientes clases lambda_xxxx miembros privados
  2. expresión lambda listas de parámetros lambda_xxxx función miembro de clase correspondientes operador () en la lista de parámetros
  3. expresión lambda de la mutable función miembro de la clase, lambda_xxxx correspondiente al operador () propiedades constantes const , es decir, si es a menudo funciones miembro
  4. lambda expresión tipo de retorno , la correspondiente lambda_xxxx función miembro de la clase de operador () tipo de retorno
  5. lambda expresión cuerpo de la función , que corresponde a la función de miembro de la clase lambda_xxxx operador función miembro ()

Además, la expresión lambda capturado, la lista de captura, también influye en el tipo correspondiente a los miembros privados de la clase lambda_xxxx

  1. La recuperación de plusvalías: el mismo tipo de variable miembro privada del tipo de captura
  2. Captura de referencia: tipo de variables miembro privadas de un tipo de referencia es capturado

No capturar las variables externas

Si la expresión lambda no capta las variables externas, bajo ciertas circunstancias, no habrá generación de código adicional.
Caracterizado porque los medios de casos específicos: hay clase lambda_xxxx a puntero de función de conversión de tipo
, tales como el código siguiente

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

Función de prueba toma un puntero a función como un argumento, y llama a la función de puntero.

Cuando la prueba llamada real, que es un parámetro pasado expresiones lambda, por lo que hay una especie de conversión implícita
lambda_xxxx => puntero a una función.

Como ya se ha mencionado, la expresión lambda es normalmente no debería existir para convertir entre una clase de objeto anónimo lambda_xxxx, un puntero de función, pero el código anterior no tiene ningún problema.

La clave es su problema, el código anterior, expresión lambda no capta las variables externas, es decir, la clase lambda_xxxx no tiene variables miembro, el operador () no se puede utilizar en cualquier variable de miembros, es decir, el operador () Aunque se trata de una función miembro, no se puede confiar en esta llamada.

Debido a que no se basan en esto, así que puede haber una transición entre una clase de objeto lambda_xxxx anónima puntero de función.

Sustancialmente como sigue:

  1. En lambda_xxxx generar una clase función estática , en función de la firma de la función estática y el operador () consistente con , en esta función estática por un puntero nulo a la clase de operador llamando al ()
    2. Tipo de sobrecarga lambda_xxxx punteros de función de conversión operador, en esta función, el primer paso en las funciones estáticas remite.

El código siguiente código después de compilador de traducción:

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);
}

En el código anterior simplemente __stdcall convención de llamada ejemplo puntero de función, el uso real diferentes convenciones de llamada, generarán la versión correspondiente de las funciones de conversión de tipo estático y la función

Estas conclusiones corrección mediante una llamada explícita para demostrar la función de conversión y desmontaje de lambda

void LambdaDemo()
{
	auto lambda = [](int i) {return i;};
	Func func = lambda.operator Func();
	Test(func);
}
  • Convertido a los punteros de función

1png

738 x 691 221 x 114

  • La función lambda_invoker_stdcall función de conversión de dirección estática como un tipo de valor de retorno

2PNG

  • lambda_invoker_stdcall función estática usando 0 ya que este operador de llamada ()

3png

Supongo que te gusta

Origin www.cnblogs.com/cute/p/12455769.html
Recomendado
Clasificación