C++: Lambda 表达式

Lambda 表达式是最小的编程语言。即使没有任何数据类型,Lambda 表达式仍然可以用来表达任何的图灵机。

在程序设计语言中,它是一段:

简短的,未被(不值得被)命名的,简短的代码片段,应该被一次性使用的一系列操作。但比起声明一个函数来说,它简洁干净,可以直接内嵌于需要调用的地方,而不用繁琐地先定义再调用。

想要了解更多有关 Lambda 表达式的内容, 这里有一个简介,应该可以让你快速了解什么是 Lambda 表达式。

从 C++ 11 开始,C++ 也引入了对 Lambda 表达式的支持。本文介绍在 C++ 中如何(优雅地)使用 Lambda 表达式。

简介

首先是 Lambda 表达式在 C++ 中的形式如下:

[ captures ]( params ) -> ret { body };

解释一下下列各项:

捕获列表 (captures):

捕获该 lambda 所在的位置可用的变量。有以下这些捕获方式:

    • [] 无捕获
    • [=] 以拷贝的方式(即按值传递)捕获所有变量 (不推荐)
    • [&] 以引用的方式捕获所有变量(不推荐)
    • [x] 以拷贝的方式捕获变量 x
    • [&x] 以引用的方式捕获变量 x

注意你可以把多种的捕获方式一起使用,例如:

  • [x, &y] 以拷贝的方式捕获变量 x,同时以引用的方式捕获变量 y
  • [&, y] 以引用的方式捕获所有变量,但以拷贝的方式捕获 y

[] 不能被省略,即使不捕获任何变量。

参数列表 (Parameters)

和函数类似,Lambda 表达式当然也可以传入参数。不过在这里和函数不一样的是,Lambda 表达式如果没有传入参数,那么这个参数列表可以连同括号一起省略。

例如:

[] { return 1; } 与 [] () { return 1; } 等价。

返回类型 (Return Type)

和函数类似,Lambda 表达式也有返回类型。但是和函数不同的是,大多数时候这个返回类型是可以省略的,编译器会帮你自动推断返回类型。(也就是说大部分时候其实根本不需要在乎这个部分 hhh)

函数体 (Body)

和函数类似,Lambda 表达式当然也有函数体。在这里写下你要进行的操作吧!

为什么我们要用 Lambda 表达式?

其实之前有提到,使用 Lambda 表达式的最大好处是可以直接在需要传入函数指针或是函数对象的时候直接写一个 Lambda。现在我们就来实践一下:

例如这个例子:C++ STL: 自定义 std::set 的排序方式

让我们把它改成用 Lambda 表达式的形式吧。

/*
 * Taking the incoming strings and outputting them in the order of their length.
 * Using Lambda to simplify the comparator
 *
 */
#include <iostream>
#include <set>
#include <functional>
using namespace std;

int main()
{
    int count;
    cin >> count;

    // function<_Rp, ..._ArgTypes> is a function wrapper introduced in header <functional>.
    // You can use function pointers instead.
    set<string, function<bool(const string&, const string&)>> strSet(
            [](const string& lhs, const string& rhs) {
                if (lhs.length() == rhs.length())
                    return lhs < rhs;

                return lhs.length() < rhs.length();
            });

    for (int i = 0; i < count; i ++)
    {
        string tmp;
        cin >> tmp;
        strSet.insert(tmp);
    }

/* -- Old school C++ enumerating. -- */
//    set<string, function<bool(const string&, const string&)>>::iterator itor;
//    for (itor = strSet.begin(); itor != strSet.end(); itor ++)
//    {
//        cout << *itor << endl;
//    }
/* -- End of enumerating. -- */

/*- From C++ 17(?):
    A new way to enumerate items in a enumerable set. -*/
    for (const auto& str : strSet)
    {
        cout << str << endl;
    }
/*- End of enumerating. -*/

    return 0;
}

像这样,我们就把外面一长串的比较器直接用 Lambda 表达式 inline 在了声明 set 的那一行里,这样让我们的代码清爽了许多。

发表评论

电子邮件地址不会被公开。 必填项已用*标注