C++11里面的Lambda表达式

时间:2023-03-08 17:40:00
C++11里面的Lambda表达式

Lambda Expressions in C++

C++中的Lambda表达式
In Visual C++, a lambda expression—referred to as a lambda—is like an anonymous function that maintains state and can access the variables that are available to the enclosing scope. This article defines what lambdas are, compares them to other programming techniques, describes their advantages, and provides a basic example.

在VC++中,一个lambda表达式——指的是一个lambda(希腊字母)——就像匿名函数一样,保持状态并可访问变量(在作用域(enclosing scope)中有效的)。这篇文章定义了什么叫做Lambda表达式,将它与其他编程技术相比,描述其优越性并提供了基础的例子。

About Lambdas

Many programming languages support the concept of an anonymous function, which is a function that has a body, but doesn't have a name. A lambda is a programming technique that's related to anonymous functions. A lambda implicitly defines a function object class and constructs a function object of that class type. For more information about function objects, see Function Objects.
许多编程语言支持匿名函数的概念,匿名函数是有函数体却没有名称的函数。Lambda正是依赖匿名函数的一种新技术。(隐式的)Lambda表达式定义了一个函数类,并以它(函数类)作为函数对象(类实例化对象,详见百度百科)。预知更多,参考MSDN库有关Function Objects的介绍。

Function Objects vs. Lambdas

When you write code, you probably use function pointers and function objects to solve problems and perform calculations, especially when you use STL algorithms. Function pointers and function objects have advantages and disadvantages—for example, function pointers have minimal syntactic overhead but do not retain state within a scope, and function objects can maintain state but require the syntactic overhead of a class definition.

A lambda combines the benefits of function pointers and function objects and avoids their disadvantages. Like a function objects, a lambda is flexible and can maintain state, but unlike a function object, its compact syntax doesn't require a class definition. By using lambdas, you can write code that's less cumbersome and less prone to errors than the code for an equivalent function object.

The following examples compare the use of a lambda to the use of a function object. The first example uses a lambda to print to the console whether each element in a vector object is even or odd. The second example uses a function object to accomplish the same task.

当你写代码时,你可能会用到函数指针,或函数对象来解决问题或者进行演算,尤其当你用STL algorithms时。函数指针和函数对象(或许可理解为仿函数?)有优缺点——例如,函数指针有最小的句法开销(?)但不能在作用域中保持状态(?),而函数对象能够保持状态却需要一个类的定义(相较而言较大的句法开销)

Lambda表达式融合了他们的优缺点。就像函数对象,Lambda表达式很灵活(于此伴生的是很难理解!!)并可保持状态,不想函数对象,它完整的句法并不需要类的定义。使用lambda表达式可以让你的代码不那么繁琐、并减少出错。
下述几个例子比较了lambda表达式和函数对象。第一个例子使用了lambda表达式在控制台中输出了在Vector容器中的元素的奇偶性。第二个采用了函数对象实现了同样的任务。

Example 1: Using a Lambda

This example uses a lambda that's embedded in the for_each function call to print to the console whether each element in a vector object is even or odd.
这个例子采用了内嵌在for_each函数中的lambda表达式,在控制台中输出vector中元素的奇偶性。
// even_lambda.cpp
// compile with: cl /EHsc /nologo /W4 /MTd
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std; int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 0; i < 10; ++i) {
v.push_back(i);
} // Count the number of even numbers in the vector by
// using the for_each function and a lambda.
int evenCount = 0;
for_each(v.begin(), v.end(), [&evenCount] (int n) {
cout << n; if (n % 2 == 0) {
cout << " is even " << endl;
++evenCount;
} else {
cout << " is odd " << endl;
}
}); // Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}

Output

0 is even
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
There are 5 even numbers in the vector.

Comments

In the example, the third argument to the for_each function is a lambda. The [&evenCount] part specifies the capture clause of the expression, (int n) specifies the parameter list, and remaining part specifies the body of the expression.

在这个例子中,第三个for_each的参数是一个lambda表达式。所谓[&evenCount]部分,明确说明了分句表达式,(int n)明确说明了一个形参(参数?)列表,剩余部分是表达式的主体。

Example 2: Using a Function Object

Sometimes a lambda would be too unwieldy to extend much further than the previous example. The next example uses a function object instead of a lambda, together with the for_each function, to produce the same results as Example 1. Both examples store the count of even numbers in a vector object. To maintain the state of the operation, the FunctorClass class stores the m_evenCount variable by reference as a member variable. To perform the operation, FunctorClass implements the function-call operator, operator(). The Visual C++ compiler generates code that is comparable in size and performance to the lambda code in Example 1. For a basic problem like the one in this article, the simpler lambda design is probably better than the function-object design. However, if you think that the functionality might require significant expansion in the future, then use a function object design so that code maintenance will be easier.

For more information about the operator(), see Function Call (C++). For more information about the for_eachfunction, see for_each.

有时候lambda表达式过于繁杂(扩充功能)。下一个例子采用了函数对象,同样使用for_each。都是数vector元素中偶数个数,为保持操作状态,FunctorClass类保存了m_evenCount变量作为一个成员变量的引用。为实现功能,FunctorClass重载(implement?)了function-call操作符,operator()。VC++编译器产生了与之相当大小和表现得lambda表达式代码(例一)。在这个基本问题中,简易的lambda表达式设计可能比函数对象更好。然而,若你认为functionality(函数性?)可能需要一个明确的扩展,那么就用函数对象写代码,那会简单些。

欲知operator()和for_each,参考Function Call(C++),for_each,在MSDN库内有。
// even_functor.cpp
// compile with: /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std; class FunctorClass
{
public:
// The required constructor for this example.
explicit FunctorClass(int& evenCount)
: m_evenCount(evenCount)
{
} // The function-call operator prints whether the number is
// even or odd. If the number is even, this method updates
// the counter.
void operator()(int n) const
{
cout << n; if (n % 2 == 0) {
cout << " is even " << endl;
++m_evenCount;
} else {
cout << " is odd " << endl;
}
} private:
// Default assignment operator to silence warning C4512.
FunctorClass& operator=(const FunctorClass&); int& m_evenCount; // the number of even variables in the vector.
}; int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 0; i < 10; ++i) {
v.push_back(i);
} // Count the number of even numbers in the vector by
// using the for_each function and a function object.
int evenCount = 0;
for_each(v.begin(), v.end(), FunctorClass(evenCount)); // Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}

Summary

Lambdas are a powerful and expressive programming technique. To learn about the parts and properties of a lambda, see Lambda Expression Syntax. To learn how to use lambdas in your programs, see Examples of Lambda Expressions.

Lambda表达式是一个强有力的编程技术。欲知更多,kNLambda Expression Syntax,http://msdn.microsoft.com/en-US/library/dd293603。更多例子在:http://msdn.microsoft.com/en-US/library/dd293599