C++11 -- expresiones lambda

Introducción de la expresión lamaba

  • Antes de C++ 11, si queremos ordenar los bienes de tipo personalizado, podemos ordenarlos según el nombre, el precio y el número de estudiante de mayor a menor o de menor a mayor. Sin embargo, necesitamos escribir 6 Functor relacionados adicionales .
  • Y en el proceso de nombrar el funtor personalizado, es fácil causar problemas de interpretación del código debido a la nomenclatura irregular.Es imposible entender la función real solo por el nombre del funtor, y solo podemos encontrar el funtor de la función correspondiente. nombre para entender función real.
struct Goods
{
    
    
	string _name;  //名字
	double _price; //价格
	int _num;      //数量
};

struct ComparePriceLess
{
    
    
	bool operator()(const Goods& g1, const Goods& g2)
	{
    
    
		return g1._price < g2._price;
	}
};
struct ComparePriceGreater
{
    
    
	bool operator()(const Goods& g1, const Goods& g2)
	{
    
    
		return g1._price > g2._price;
	}
};
struct CompareNumLess
{
    
    
	bool operator()(const Goods& g1, const Goods& g2)
	{
    
    
		return g1._num < g2._num;
	}
};
struct CompareNumGreater
{
    
    
	bool operator()(const Goods& g1, const Goods& g2)
	{
    
    
		return g1._num > g2._num;
	}
};
int main()
{
    
    
	vector<Goods> v = {
    
     {
    
     "苹果", 2, 20 }, {
    
     "香蕉", 3, 30}, {
    
     "橙子", 4,40 }, {
    
     "菠萝", 5,50 } };
	sort(v.begin(), v.end(), ComparePriceLess());    //按Goods价格升序排序
	sort(v.begin(), v.end(), ComparePriceGreater()); //按Goods价格降序排序
	sort(v.begin(), v.end(), CompareNumLess());      //按Goods升序排序
	sort(v.begin(), v.end(), CompareNumGreater());   //按Goods降序排序
	return 0;
}


Después de C ++ 11, podemos usar la expresión lamada para resolver el problema. La expresión lamada es en realidad una función anónima, por lo que podemos entender directamente el método de comparación de clasificación a través de la expresión lamada, mejorando así la legibilidad del código. sexo.

int main()
{
    
    
	vector<Goods> v = {
    
     {
    
     "苹果", 2.1, 300 }, {
    
     "香蕉", 3.3, 100 }, {
    
     "橙子", 2.2, 1000 }, {
    
     "菠萝", 1.5, 1 } };
	sort(v.begin(), v.end(), []( const Goods& g1,const Goods& g2) {
    
    return g1._price < g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
    
    return g1._price < g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
    
     return g1._num < g2._num; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
    
     return g1._num < g2._num; });
	return 0;
}


sintaxis de la expresión lambda

El formato de escritura de la expresión lamada:

[capture-list] (parameters) mutable -> return-type 
{
    
      
  statement
}

Explicación de cada parte de la expresión lambda

  • [capture-list]: la lista de captura, que siempre aparece al comienzo de la expresión lambda, el compilador juzgará si el siguiente código es una expresión lambda de acuerdo con [], la lista de captura puede hacer la expresión lambda de acuerdo con las variables en la expresión de contexto utilizada.
  • (parámetros): La lista de parámetros, que es consistente con la lista de parámetros normal. Si no necesita pasar parámetros, puede omitirlos junto con ().
  • mutable: de forma predeterminada, una expresión lambda siempre es una función const (el parámetro de la función no se puede modificar), y mutable puede cancelar la constness. Cuando se usa este modificador, la lista de parámetros no se puede omitir (incluso si la lista de parámetros es nula.
  • ->returntype: Tipo de valor de retorno Generalmente, debido a que el compilador deduce el tipo de retorno, se puede omitir cuando el valor de retorno es claro.
  • {sentencia}: Cuerpo de la función En este cuerpo de la función, además de los parámetros formales en el cuerpo de la función, también se pueden usar todas las variables capturadas.

Uso simple de expresiones lambda

int mian()
{
    
    
	//由于lambda表达式实际上就是一个匿名对象,没有函数名不好调用,但是我们可以通过auto自动获取.
	auto add1 = [](int a, int b) {
    
     return a + b; };    //省略返回值.

	cout << add1(1, 2) << endl;

}

descripción de la lista de capturas

La lista de captura describe qué datos en el contexto puede usar la lambda y si se usan por valor o por referencia.

  • [var]: Indica que el método de transferencia de valor captura la variable var.
  • [=]: indica que el método de transferencia de valor captura todas las variables en el ámbito principal (incluido este).
  • [&var]: Indica que la variable de captura var se pasa por referencia.
  • [&]: indica que la transferencia de referencia captura todas las variables en el ámbito principal (incluido este).
  • [this]: indica que el método de transferencia de valor captura el puntero this actual.

La comparación entre no usar la lista de captura y usar la lista de captura en la expresión lambda.

Si no aplicamos la lista de captura, tenemos que escribir parámetros de función adicionales, y los parámetros reales también deben pasarse al llamar, lo cual es demasiado problemático.

int main()
{
    
    
	//之前做法
	int x = 0,y = 1;
	
	auto swap1 = [](int& x1, int& x2) {
    
     int tmp = x1; x1 = x2; x2 = tmp;};

	swap1(x, y);

	return 0;
}

Por lo tanto, podemos usar la lista de captura, y debido a que x e y capturados por valor generalmente no son modificables (se puede usar el modificador mutable), y x e y capturados en este momento son solo copias de los parámetros reales. generalmente usa la captura de referencia, lo que hace que el código sea más conciso.


int main()
{
    
    
	auto swap2 = [&x, &y] {
    
    int tmp = x; x = y; x = tmp;}; //引用捕捉.
    
	swap2();             //不需要传递实参.
	
	cout << x << ":" << y << endl;
	
}

Uso simple de otras características de la lista de captura

int main()
{
    
    
	int a, b, c, d, e;
	
	auto f1 = [=] {
    
    cout << a << b << d << e; }; //a,b,c,d,e全部传值捕获.

	f1();

	auto f2 = [=, &a] {
    
     a++; cout << a << b << c << d << e; }; //b,c,d,e传值捕获,a传引用捕获.

	f2();
	
}

Pero tenga en cuenta que la lista de captura no permite que las variables se pasen repetidamente, de lo contrario, se producirán errores de compilación.

int main()
{
    
    
	int a, b, c, d, e;
	
	auto f = [=,a] {
    
    cout << a << b << d << e; }; //重复捕获.

}

Exploración del principio subyacente de la expresión lamaba

El tratamiento de las lambdas por parte del compilador es en realidad el mismo que el de los funtores .

Para verificar los principios subyacentes de las expresiones lambda, escribimos un funtor y una expresión lambda respectivamente, y sus funciones son las mismas.

class Rate
{
    
    
public:
	Rate(double rate) : _rate(rate)
	{
    
    }
	double operator()(double money, int year)
	{
    
    
		return money * _rate * year;
	}
private:
	double _rate;
};
int main()
{
    
    
	// 函数对象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);
	// lamber表达式
	auto r2 = [=](double monty, int year)->double {
    
    return monty * rate * year;
	};
	r2(10000, 2);
	return 0;
}

Cuando llamemos al funtor y la expresión lambda por separado, vaya a la vista de desensamblaje.
inserte la descripción de la imagen aquí

Resumen :

  • Desde el punto de vista del uso, el funtor es exactamente igual que la expresión lambda. El objeto de función usa la tasa como su variable miembro, y el parámetro real se puede pasar al definir el objeto. La expresión lambda puede capturar directamente la variable para el parámetro real que pasa a través de la lista de captura.
  • Desde la perspectiva de la implementación subyacente, se procesa completamente en forma de funtores. Cuando definimos una expresión lambda, el compilador generará activamente un funtor y, para facilitar el procesamiento, el compilador debe usar UUID Básicamente generar un único nombre del funtor. Luego llame a este funtor a través de una expresión lambda al llamar, y el funtor llama al operador para sobrecargar operator (). Entonces, de hecho, las variables capturadas por la lista de captura se pasan a operator () implementada en el cuerpo de la función .

Supongo que te gusta

Origin blog.csdn.net/m0_63300413/article/details/130877704
Recomendado
Clasificación