一文提高对lambda表达式理解

194 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

C++11中lambda特性

  1. lambda不支持重载,但是函数对象可以
class Cap
{
public:
	bool operator()(int a, int b) { return a < b; }
	bool operator()(float a, float b) { return a < b; }

};
  1. lambda不支持捕获具有静态存储时间的变量,如全局变量,静态变量
  2. mutable特性的lambda不能保存于const类型变量,类型不匹配
	const auto f = [vec]()mutable {
		for (auto i : vec)
		{
			std::cout << i;
		}
	};
  1. lambda表达式不能捕获成员变量,用this捕获即可
  2. 当捕获对象的生命周期小于lambda,则出现未定义行为
struct Baz
{
	std::function<void()> f()
	{
		return [=]() {
			std::cout << s << "\n";
		};
	}

	std::string s;
};


void test()
{
	auto f1 = Baz{ "111" }.f();
	auto f2 = Baz{ "222" }.f();
	f1();
	f2();
}

这种问题的解决方法为(大于等于C++14):

struct Baz
{
	std::function<void()>f()
	{
		return [ss=s]//这里是重点,将变量s保存到闭包中
		() 
		{
			std::cout << ss << "\n";
		};
	}

	std::string s;
};
  1. 针对只移型别的对象不可按值捕获,可以通过引用捕获
	std::unique_ptr<int> uptr = std::unique_ptr<int>(new int(10));
	auto f = [&uptr]() {};
  1. 不捕获任何变量的lambda可以转换为函数指针
  2. The closure type associated with a lambda-expression has a deleted default constructor and a deleted copy assignment operator.
  3. The value of the value-captured variable is at the time the lambda is defined - not when it is used! The value of a ref-captured variable is the value when the lambda is used - not when it is defined.
  4. The C++ closures do not extend the lifetimes of the captured references. Be sure that the capture variable still lives when lambda is invoked.

C++14中lambda新特性

  1. 支持参数具有默认值
	auto f = [](int x=10) {
		std::cout << x << "\n";
	};

	f();
	f(100);
  1. 支持带初始化列表的捕获
	int x = 10;
	auto f = [xx = x]//按值
	() {
		std::cout << xx << "\n";
	};
	f();//10
	x = 100;
	f();//10
	int x = 10;
	auto f = [&xx = x]//按引用
	() {
		std::cout << xx << "\n";
	};
	f();//10
	x = 100;
	f();//100
  1. 支持通用模板
	auto f = [](auto x,int y) {
		std::cout << x <<","<<y << "\n";
	};

	f(100, 0);
	f("hello", 1);
	f(1.2f, 2);
	f(1.6, 3);

C++17中lambda新特性

  1. 支持*this捕获,适用于lambda表达式的生命周期大于对象的生命周期
  • this和*this的取舍
In most cases, when you work inside the scope of a class, then [this] (or [&]) is perfectly fine. There’s no extra copy which is essential when your objects are large. You might consider [*this] when you really want a copy, and when there’s a chance a lambda will outlive the object.
  1. 支持std::invoke()实现立即调用,代替lambda表达式末尾的()
	int x = 100, y = 0;
	std::invoke([x = x, y = y]() {
		std::cout << x <<","<<"  "<<y << "\n";
		}) ;
A lambda expression can read the value of a variable without capturing it if the variable 
- has const non-volatile integral or enumeration type and has been initialised with a constant expression, or
- is constexpr and has no mutable members.