前面讲过,lambda表达式可以按传值或者引用捕捉在其作用域范围内的变量。而有时候,我们希望捕捉不在其作用域范围内的变量,而且最重要的是我们希望捕捉右值。所以C++14中引入了表达式捕捉,其允许用任何类型的表达式初始化捕捉的变量,如下:
// 利用表达式捕获,可以更灵活地处理作用域内的变量 int x = 4; auto y = [&r = x, x = x + 1] { r += 2; return x * x; }(); // 此时 x 更新为6,y 为25 // 直接用字面值初始化变量 auto z = [str = "string"] { return str; }(); // 此时z是const char* 类型,存储字符串 string可以看到捕捉表达式扩大了lambda表达式的捕捉能力,有时候你可以用std::move初始化变量。这对不能复制只能移动的对象很重要,比如 std::unique_ptr,因为其不支持复制操作,你无法以值方式捕捉到它。但是利用lambda捕捉表达式,可以通过移动来捕捉它:
auto myPi = std::make_unique<double>(3.1415); auto circle_area = [pi = std::move(myPi)](double r) { return *pi * r * r; }; cout << circle_area(1.0) << endl; // 3.1415 泛型lambda表达式从C++14开始,lambda表达式支持泛型:其参数可以使用自动推断类型的功能,而不需要显示地声明具体类型。这就如同函数模板一样,参数要使用类型自动推断功能,只需要将其类型指定为auto,类型推断规则与函数模板一样。这里给出一个简单例子:
auto add = [](auto x, auto y) { return x + y; }; int x = add(2, 3); // 5 double y = add(2.5, 3.5); // 6.0 函数对象函数对象是一个广泛的概念,因为所有具有函数行为的对象都可以称为函数对象。这是一个高级抽象,我们不关心对象到底是什么,只要其具有函数行为即可。函数行为是指可以使用()调用并传递参数,如下所示:
function(arg1, arg2, ...); //函数调用由此,lambda表达式也是一个函数对象。该函数对象实际上是一个匿名类的实例,且这个类实现了函数调用运算符()。
泛型提供了高级抽象,不论是lambda表达式、函数对象、还是函数指针,都可以传入到STL算法中(如for_each)。