C++:函数对象:Lambda:Lambda详解(三)

1:定义

  • lambda表达式就是一个函数(匿名函数),也就是一个没有函数名的函数。为什么不需要函数名了? 因为我们直接(一次性的)用它,不需要其他地方调用它。
  • lambda表达式也叫闭包,闭就是封闭的意思(就是其他地方都不调用它),包就是函数
  • lambda表达式其实就是一个函数对象,它内部创建了一个重载()操作符的类
  • lambda表达式的简单语法如下:
  • [capture] (paramters) ->return value {body},只有[capture] 捕获列表和 {body} 函数体是必选的,其他可选。

2:最简单的一个 lambda表达式(调用) 

int main() 
{
    // [] 代表 lambda表达式的开始
       () 代表 函数调用
       {} 代表 函数体 

    // lambda表达式
    [] () {} 
}


// 上述表达式等价于

void f()
{

}

int main()
{
    f();
}

3: lambda表达式调用 

#include<iostream>
#include<string>

using namespace std;

int main()
{
    // 省略 表达式的 形参和返回值
    [] {cout << "hello world"<< endl;};

    // 或者这样写
    auto lam = [] {cout << "hello world"<< endl;};
    lam();
}

4: 返回值 

-> int : 代表此匿名函数返回 int  

 大多数情况下  lambda 表达式的返回值可由编译器猜测出阿里,因此我们不需要指定返回值类型。

int main()
{
    // 编译器可以自动推导出 函数体返回值,可以省略 返回int 返回类型
    auto lam = []() -> {cout << "hello,world"; return 88;};

    // 等价于
    auoto lam2 = [](){cout << "hello,world"; return 88;};

    auto ret = lam();
    cout << ret<< endls;  // 打印 88

    auto lam3 = [](){cout<< "hello world"; return "test str"};
    auto ret3 = lam3();
    cout << ret3 << endls;  // 打印 test str
}

5: 捕捉变量 

变量捕获才是  lambda最卓越的秘方。

  1. [ ]   ----- 不捕获任何变量,这种情况下 lambda 表达式内部不能访问外部变量
  2. [&]  -----以引用方式捕获所有变量
  3. [=] ------用值得方式捕获所有变量 (也有可能被编译器优化为 const &)

[=, &foo]  ----以引用的方式捕获 foo 变量,其他变量通过值方式捕获

[&, foo]  ---- 以值方式捕获 foo 变量,其他变量靠引用捕获

[bar] ------以值方式捕获bar变量,不捕获其他变量

[this] ------捕获所在类的this 指针 (在QT中使用的比较多,如此lambda可以通过this方位界面控件的数量。)

int main()
{
    int a = 1,b=2,c=3;
    auto lam2 = [&,a] ()
    {

        // a以值得方式捕获,b和c以引用方式捕获
        b = 4, c= 5;
        a = 6;  // error : a是不可修改的左值
        
        // 打印输出:1 4 5
        cout<< a << b << c<<enld;  
    };
    lam2();
}

6: lambda 在 STL中算法库中应用

毋庸置疑:  lambda表达式最大的一个优势是在 使用 STL中的算法(algorithms)库应用。

案例1:循环打印容器中的数据

vector<string> address = {"1111","222","333","org","www"};

int mian()
{
    for_each(address.begin(), address.end(),[](const string& str){

         cout<< str << endl;
    });
}

案例2: 给数组排序

// 数组代码排序(自己写一个降序接口)

int arr[] = {6,10,8,9,2,5};

bool compare(int& a, int& b) {
    // 降序排序
    return a>b;
}

std::sort(arr,arr+6 ,compare);



// 给数组排序(lambda表达式)
str::sort(arr,arr+6, [](const int& a, const int& b){
        return a>b; 
});

// 优化 C++14 支持基类类型推导的泛型
str::sort(arr,arr+6, [](const auto& a, const auto& b){
        return a>b; 
});

// 打印排序后的数据
std::for_each(begin(arr),end(arr), [](const int& a) {
    cout<< "After sort: " << a;
});

7:  创建lambda函数的一个原因是:有些人创建了一个希望接受(lambda函数)参数的函数

  1. lambda 的引入给我吗带来一种全新的编程体验,它可以让我们把  "function" 当做是“data”一样传递,并且使我们从繁琐的语法中解放出来,更加关注 “算法”本身。
  2. 新的 std::function 是传递lambda函数的最好方式,不管是传参数还是传返回值
  3. 以下代码:将lambda表达式作为函数参数传递,程序作用很简单,是从一个地址薄中查找满足条件的地址(匹配字符串或者长度规则)
#include<iostream>
#include<string>
#include<vector>
#include<functional>
#include<algorithm>

using namespace std;

class AddressBook
{
public:
	// 提供一个通用的查找方法,以供查询(匹配的地址),这个方法接受一个查找规则的函数作为参数。
	std::vector<string> findMatchingAddress(std::function<bool(const string&)> func)
	{
		std::vector<string> results;
		for (auto it = _addresses.begin(),end = _addresses.end();it != end; ++it)
		{
			// 调用传递到 findMatchingAddresses的函数并检测是否匹配规则
			if (func(*it))
			{
				results.push_back(*it);
			}
		}
		return results;
	}

	void SetAddress(const std::vector<std::string>& address) {
		_addresses = address;
	}

private:
	std::vector<string> _addresses;
};

// 声明一个全局的 AddressBook对象。
AddressBook global_address_book;

// 查找匹配名字的地址
vector<string> findAddressesFromName(const string& name)
{
	return global_address_book.findMatchingAddress(
		[&](const string& addr) { 
			return addr.find(name) != string::npos; 
		}
	);
}

// 查找匹配长度的地址(大于 min_len)
vector<string> findAddressLen(const size_t& min_len) {
	return global_address_book.findMatchingAddress(
		[&](const string& addr) {
			return addr.length()>= min_len;
		}
	);
}

int main() {
	// 初始化 AddressBook 对象的成员 _addresses
	vector<string> address{ "china chengdu","china wuhan",
		"china guangzhou","japan dongjing","Americal huashengdun"};
	global_address_book.SetAddress(address);

	// 查找包含china的地址
	auto ret = findAddressesFromName("china");
	for_each(ret.begin(), ret.end(), [](string& str) {
		cout << str << " ";
		});
	cout << endl;

	// 查找长度大于15的地址
	auto ret2 = findAddressLen(15);
	for_each(ret2.begin(), ret2.end(), [](string& len) {
		cout << len << " ";
		});

}

 请注意看下面这个问题:std::function<> func : 泛型返回值和入参均要和实参对应。

 

猜你喜欢

转载自blog.csdn.net/u013620306/article/details/128654702