c++Lambda

Lambda 表达式不仅具有函数指针的灵活性,还可以通过捕获局部变量提高可扩展性。本文介绍 Lambda 表达式的语法和用法。

简介

Lambda 可能是最新的 C++11 标准的典型特性之一。Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。

当一个函数需要将另一个函数用作参数时,可以使用 Lambda。例如,C qsort() 函数接受一个指向比较函数的指针,如清单 1 所示。

#include <stdlib.h> 
 #include <stdio.h> 
 static int intcompare(const void *p1, const void *p2) 
 {   
 int i = *((int *)p1);  
 int j = *((int *)p2); 
 return (i < j) ;
 }  
 int main() 
 {   
 int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; 
 qsort((void *)a, 10, sizeof (int), intcompare);
 for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }  
 printf("
"); 
 return 0;  }

清单 1

清单 1 中的代码有以下几点不足:

  • 比较函数需要单独声明。这增加了将错误的比较函数传递给 qsort() 操作的风险。
  • 比较函数接受 void * 参数,因此缺失了某种程度的类型检查。
  • 比较函数看不到任何局部作用的变量。因此,如果存在其他影响排序的因素,必须在更大范围内声明。

清单 2 显示重新编写后的清单 1 中的示例,将 C++ std::sort() 算法与 lambda 表达式结合使用。由于 std::sort() 是一个模板,因此会保留所有类型信息。注意如何在通常出现函数名的位置编写 lambda 表达式。

#include <algorithm> 
 int main() 
 {
 int a[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };   
std::sort( a, &a[10], [](int x, int y){ return x < y; } );
    for(int i=0; i<10; i++) { printf("%i ", a[i]); }  
  printf("
");    
  return 0; 
  }

清单 2

Lambda 表达式的基本语法

Lambda 表达式本质上与函数声明非常类似。我们可以提取清单 2 中的 lambda 表达式,详加说明。提取的 lambda 表达式如清单 3 所示:

[](int x, int y){ return x < y ; }

清单 3

如果我们将 lambda 表达式比作函数,可以看到它与函数名对应的是一对空的方括号,即捕获表达式。这些括号表示后面跟着一个 lambda 表达式。这些方括号不必为空;稍后将讨论其内容。

如果 lambda 主体只含一个返回类型,则暗示返回的表达式类型为 lambda 返回类型。如果要显式指定返回类型,需使用新的 C++11 语法表示函数声明中的后置返回类型。对于返回类型 T 的普通函数,您可以这样编写:

auto foo(...) -> T { ... }

对于 lambda,您需要要这样编写:

[] (...) -> T { ... }

lambda 表达式的其余部分与常规 C 或 C++ 函数主体类似。

将 Lambda 传递到函数指针

C++11 标准库中有一个名为 function 的模板,它可以接受指定类型的函数或者具有匹配的返回类型和参数列表的 lambda。这将产生一个指向函数类型的指针,例如,清单 4 可用作函数参数类型,接受 int 参数,返回 void。您可以向其传递任何类似匹配函数或 lambda 的内容。

std::function<void(int)>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

bool cmp(int a, int b)
{
    return  a < b;
}

int main()
{
    vector<int> myvec{ 3, 2, 5, 7, 3, 2 };
    vector<int> lbvec(myvec);

    sort(myvec.begin(), myvec.end(), cmp); // 旧式做法
    cout << "predicate function:" << endl;
    for (int it : myvec)
        cout << it << ' ';
    cout << endl;

    sort(lbvec.begin(), lbvec.end(), [](int a, int b) -> bool { return a < b; });   // Lambda表达式
    cout << "lambda expression:" << endl;
    for (int it : lbvec)
        cout << it << ' ';
}
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
     int a = 900;
     auto f = [a] { cout << a << endl; };  
     cout <<  ++a << endl;
     return 0;
}
root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
root@ubuntu:~/c++# ./lam 
901
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
     int a = 900;
     auto f = [a] { cout << ++a << endl; };
     f();
     cout <<  ++a << endl;
     return 0;
}
root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
lam.cpp: In lambda function:
lam.cpp:7:31: error: increment of read-only variable ‘a’
      auto f = [a] { cout << ++a << endl; }; 
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
     int a = 900;
     auto f = [&a] { cout << ++a << endl; };
     f();
     cout <<  ++a << endl;
     return 0;
}
root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
root@ubuntu:~/c++# ./lam 
901
902
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
     int a = 900;
     auto f = [](int a) mutable { cout << ++a  << endl; };
     f(300);
     cout <<  ++a << endl;
     return 0;
}
root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
root@ubuntu:~/c++# ./lam
301
901
root@ubuntu:~/c++# 
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
     int a = 900;
     auto f = [](int b) { cout << ++a + b << endl; };
     f(300);
     cout <<  ++a << endl;
     return 0;
}
~
lam.cpp: In lambda function:
lam.cpp:7:37: error: ‘a’ is not captured
      auto f = [](int b) { cout << ++a + b << endl; }; 
                                     ^
lam.cpp:7:16: note: the lambda has no capture-default
      auto f = [](int b) { cout << ++a + b << endl; }; 
                ^
lam.cpp:6:10: note: ‘int a’ declared here
      int a = 900;
          ^

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a = 900;
[](int a) mutable { cout << ++a << endl; }(20);
cout << ++a << endl;
return 0;
}

root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
root@ubuntu:~/c++# ./lam
21
901
#include <iostream>
#include <algorithm>
#include<functional>
using namespace std;
int main()
{
     int a = 900;
     function<int(int x)> f_display_42 = [](int x) { return ++x; };
     cout << f_display_42(44) << endl;
     cout <<  ++a << endl;
     return 0;
}
root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
root@ubuntu:~/c++# ./lam
45
901
#include <iostream>
#include <algorithm>
#include<functional>
using namespace std;
int main()
{
     int a = 900;
     function<int(int x)> f_display_42 = [a](int x) { return a+x; };
     cout << f_display_42(44) << endl;
     cout <<  ++a << endl;
     return 0;
}
root@ubuntu:~/c++# g++ -std=c++11  lam.cpp -o lam
root@ubuntu:~/c++# ./lam
944
901
捕获形式说明
[] 不捕获任何外部变量
[变量名, …] 默认以值得形式捕获指定的多个外部变量(用逗号分隔),如果引用捕获,需要显示声明(使用&说明符)
[this] 以值的形式捕获this指针
[=] 以值的形式捕获所有外部变量
[&] 以引用形式捕获所有外部变量
[=, &x] 变量x以引用形式捕获,其余变量以传值形式捕获
[&, x] 变量x以值的形式捕获,其余变量以引用形式捕获

 https://www.cnblogs.com/DswCnblog/p/5629165.html

https://www.oracle.com/cn/servers/technologies/howto-use-lambda-exp-cpp11.html

原文地址:https://www.cnblogs.com/dream397/p/14605242.html