初识C++中的lambda

初始C++中的Lambda

在使用泛型编程算法比较序列中的数据的时候,默认情况下,这些算法使用元素类型的<=运算符完成比较,比如sort,默认使用<对序列中的元素进行比较,进而完成升序排序。

但是我们可能想用其他的方式进行排序,或者我们所处理序列中的对象没有定义<运算符,比如C++ Primer 5th中自己定义的Sales_data类。这时可能需要我们去做一些定制操作对序列进行操作。

有两种方法进行定制操作:(1) 向算法传递函数;(2) lambda表达式

lambda

根据算法接受一元谓词还是二元谓词,我们传递给算法的谓词必须严格接受一个或两个参数。但是,有时我们希望进行的操作需要更多参数,超出了算法对谓词的限制。

例一

例如C++ Primer 5th中的练习10.13

练习10.13: 标准库定义了名为partition的算法,它接受一个谓词,对容器内容进行划分,使得谓词为true的值会排在容器的前半部分,而使得谓词为false的值会排在后半部分。算法返回一个迭代器,指向最后一个使谓词为true的元素之后的位置。编写函数,接受一个string,返回一个bool值,指出string是否有5个或更多字符。使用此函数划分words。打印出长度大于等于5的元素。

方法一: 向算法传递函数

template <typename Sequence> void print(Sequence const &seq);

bool cmp(const string &s) {
	return s.size() >= 5 ? true : false;	// 谓词只能接受string,无法接收划定条件,5是我们自己显示设置的
}

int main(int argc, char **argv)
{
	vector<string> v{"Cpp", "Java", "C", "Python", "C#", 
								"PHP", "JavaScript", "SQL", "Golang"};
	print(v);
	auto end_part = partition(v.begin(), v.end(), cmp);
	auto beg = v.begin();
	while (beg != end_part) {
		cout << *beg++ << " ";
	}
	cout << endl;
	return 0;
}

该方法可以完成相应的功能,但如果题目中的条件长度大于等于5更改,我们必须更改return s.size() >= 5 ? true : false;中的数值。能不能使谓词再接收一个参数sz可以指定划定条件呢?要使谓词接收多个参数,就需要使用lambda。

方法二: lambda表达式

使用lambda表达式,接收一个参数sz表示划分条件。

template <typename Sequence> void print(Sequence const &seq);

int main(int argc, char **argv)
{
	vector<string> v{"Cpp", "Java", "C", "Python", "C#", 
								"PHP", "JavaScript", "SQL", "Golang"};
	print(v);
    
    size_t sz;
    cin >> sz;
    
	auto end_part = partition(v.begin(), v.end(),
         				[sz] (const string &s) { return s.size() >= sz; }     // 捕获变量sz作为划分条件               
    );
	auto beg = v.begin();
	while (beg != end_part) {
		cout << *beg++ << " ";
	}
	cout << endl;
	return 0;
}

该程序的意义是,使得一个只能接受一个谓词的算法,接受到了两个参数。lambda还可以捕获更多参数,捕获的方式默认为值捕获[=]),其他还有引用捕获[&])。

介绍lambda

一个lambda表达式具有如下形式:

[capture list] (parameter list) -> return type { function body }

  • capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表。lambda只能使用那些明确指明的变量
  • 必须使用位置类型返回
  • 可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体
  • lambda和函数一样使用 调用运算符() 进行调用;
  • lambda不能有默认参数;
  • 如果lambda的函数体包含任何单一return语句之外的内容,且未指定返回类型,则返回void。

例二

求一个序列中大于等于一个给定长度的单词有多少。修改输出,使程序只打印大于等于给定长度的单词。

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

using namespace std;

template <typename Sequence> ostream& print(Sequence const &seq);
void elimDups(vector<string> &words);
void biggies(vector<string> &words, vector<string>::size_type sz);
string make_plural(size_t ctr, const string &word, const string &ending = "s");

int main(int argc, char **argv)
{
	vector<string> v{"Cpp", "Java", "C", "Python", "C#", 
								"PHP", "JavaScript", "SQL", "Golang"};
	print(v) << endl;

	biggies(v, 5);			// 将长度大于等于5的字符串按照字典和长度顺序排列
	print(v) << endl;

	return 0;
}

void biggies(vector<string> &words, vector<string>::size_type sz) {			// 传入sz作为划分依据
	// 按字典排序,并删除重复字符
	elimDups(words);

	// 按照字符长度排序,长度相同的字符串保持字典排序(stable)
	stable_sort(words.begin(), words.end(),  		
				[] (const string &lhs, const string &rhs) 
				{ return lhs.size() < rhs.size(); }
	);

	// 指向第一个长度小于sz的迭代器(wc之前的长度都大于sz)
	auto wc = stable_partition(words.begin(), words.end(), 		// 稳定版划分
				[sz] (const string &s) { return s.size() >= sz; }		   // 捕获sz
	);
	auto count = wc - words.begin();		// 统计有多少个大于sz的字符串
	cout << count << " " << make_plural(count, "word", "s")
	<< " of length " << sz << " or longer" << endl;

	// 将每一个长度大于sz的字符串都输出
	for_each(words.begin(), wc, [] (const string &s) { cout << s << " "; });
	cout << endl;
}

void elimDups(vector<string> &words) {
	sort(words.begin(), words.end());
	auto end_unique = unique(words.begin(), words.end());		// end_unique指向非重复字符的后一位
	words.erase(end_unique, words.end());								   // 删除end_unique到末尾的重复字符串
}

string make_plural(size_t ctr, const string &word, const string &ending) {
	return (ctr < 1) ? word : word + ending;
}

template <typename Sequence> ostream& print(Sequence const &seq) {
	for (const auto &i : seq) cout << i << " ";
	return cout;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值