zoukankan      html  css  js  c++  java
  • C++的lambda表达式

    http://blog.csdn.net/xqs83/article/details/7612866

    很多高级语言里引入了lambda表达式的概念,即匿名函数。以往C++需要传入一个函数的时候,必须事先进行声明,视情况可以声明为一个普通函数然后传入函数指针,或者声明一个funtor,然后传入一个对象。

    但这种传统方法太过复杂,一个简单的遍历输出就需要声明一个类或者函数,本来用于简化语法的东西却使语法大大复杂化。

    比如一个用随机数填充数组的例子:

    #include <iostream>
    #include <cstdlib>
    #include <iterator>
    #include <algorithm>
    using namespace std;
    
    class mi_rand
    {
        public:
            mi_rand (int start_pos, int end_pos)
            : a(start_pos), b(end_pos) 
            {}
    
            unsigned operator () () 
            {
                return rand() % (b-a+1) + a;
            }
    
        private:
            int a, b;
    };
    
    int main()
    {
        const int SIZE = 20;
        int array[SIZE];
        generate_n (array, SIZE, mi_rand (1, 30));
        
        copy (array, array + SIZE, 
              ostream_iterator<int> (cout, " "));
        cout << endl;
        
        return 0;
    }

    示例中,generate_n的目的是使填充数组的操作简单化,但为了这种简单化却要额外声明一个类。输出数组时利用STL的确能进行语法上的简化,但是这种简化却要求对STL非常了解,而且拓展性非常差。

    所幸,在c++0x标准中终于引入了lambda表达式,目前 VS 2010 和 g++ 4.5 已经进行了试验性的实现。针对上面的填充和输出操作,下面是使用lambda表达式的简化版:

    #include <iostream>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    
    int main()
    {
        const int SIZE = 20;
        int array[SIZE];
        generate_n (array, SIZE,
                    [] () { return rand() % 30 + 1; });
    
        for_each (array, array + SIZE, 
                  [] (int a){ cout << a << " "; });
        
        return 0;
    }

    编译时需要注意的是,VS要求版本在2010以上,编译时需要加上 /EHsc 参数。使用g++编译的话版本要在版本4.5以上,并加上 --std=c++0x 参数。

    g++目前(10年八月)的最新版本为4.51,你可以到 http://gcc.gnu.org/自行下载编译。ubuntu下可以通过 PPA for Ubuntu Toolchain Hackers直接安装二进制版本。


    下面将阐述lambda表达式的语法,内容主要参考自 Lambda Expression Syntax

    如图,lambda表达式由下面几个部分构成:

    1. lambda-introducer (捕获字段)
    2. lambda-parameter-declaration-list (变量列表)
    3. mutable-specification (捕获的变量可否修改)
    4. exception-specification (异常设定)
    5. lambda-return-type-clause (返回类型)
    6. compound-statement (函数体)

    外部变量的捕获规则

    默认情况下,即捕获字段为 [] 时,lambda表达式是不能访问任何外部变量的,即表达式的函数体内无法访问当前作用域下的变量。

    如果要设定表达式能够访问外部变量,可以在 [] 内写入 & 或者 = 加上变量名,其中 & 表示按引用访问,= 表示按值访问,变量之间用逗号分隔,比如 [=factor, &total] 表示按值访问变量 factor,而按引用访问 total。

    不加变量名时表示设置默认捕获字段,外部变量将按照默认字段获取,后面在书写变量名时不加符号表示按默认字段设置,比如下面三条字段都是同一含义:

    [&total, factor]
    [&, factor]
    [=, &total]

    参数列表

    lambda表达式的参数列表基本和函数的一致,不过有如下限制:

    1. 参数列表不能有默认参数
    2. 不能是可变参数列表
    3. 所有的参数必须有个变量名

    如果你不提供 mutable-specification, exception-specification, 以及 lambda-return-type-clause,参数列表是也可以省略的。如下面的表达式:

    int main()
    {
       int x = 4;
       int y = 5;
       int z = [=] { return x + y; }();
    }

    能否修改捕获的变量

    如果在参数列表后加上了 mutable,则表示表达式可以修改按值捕获的外部变量的拷贝。

    异常设置

    和函数一样,可以用 throw 来限定表达式能够抛出哪些异常。

    返回类型

    如果设置返回类型,你需要在类型名前面加上 ->。如果你只有一个返回语句的话,返回类型可以省略,编译器将会为你做出判断。

    函数体

    lambda表达式的函数体和普通函数大致相同。


    下面是lambda表达式的几个完整例子:

    #include <algorithm>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    // The number of elements in the vector.
    const int elementCount = 9;
    
    int main() 
    {
       // Create a vector object with each element set to 1.
       vector<int> v(elementCount, 1);
    
       // These variables hold the previous two elements of the vector.
       int x = 1;
       int y = 1;
    
       // Assign each element in the vector to the sum of the 
       // previous two elements.
       generate_n(v.begin() + 2, elementCount - 2, [=]() mutable throw() -> int {
          
          // Generate current value.
          int n = x + y;
    
          // Update previous two values.
          x = y;
          y = n;
    
          return n;
       });
    
       // Print the contents of the vector.
       for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });
       cout << endl;
    
       // Print the local variables x and y.
       // The values of x and y hold their initial values because 
       // they are captured by value.
       cout << x << " " << y << endl;
    }
    #include <functional>
    
    int main()
    {
       // Assign the lambda expression that adds two numbers to an auto variable.
       auto f1 = [] (int x, int y) { return x + y; }; 
    
       // Assign the same lambda expression to a function object.
       using namespace std::tr1;
       function<int (int, int)> f2 = [] (int x, int y) { return x + y; };
    }
  • 相关阅读:
    静态库与动态库的创建与使用
    MinGW 仿 linux 开发环境
    SICP 1.7-1.8 solution (Scheme)
    PHP 学生管理系统实现
    【2014最新】常用hosts集锦,分享给大家
    【Android快速入门3】布局简介及例子
    【Android快速入门2】拨号器的实现
    【Android快速入门1】目录结构及adb命令(以API19为例)
    基于深度及广度优先搜索的迷宫问题的演示
    基于HTML5的js构造爱心,动态时间校准
  • 原文地址:https://www.cnblogs.com/dps001/p/4463449.html
Copyright © 2011-2022 走看看