zoukankan      html  css  js  c++  java
  • C++11之Lambda特性探析

    目录

    目录 1

    1. 什么是Lambda 1

    2. 语法格式 1

    2.1. 语法格式 1

    2.2. 最简定义 2

    3. 应用示例 2

    4. capture列表 3

    4.1. 基本形式 3

    4.2. 注意事项 3

    5. 对比仿函数 3

    6. 对比函数指针 4

    7. LamdbaSTL 4

    8. 参考资料 5

    1. 什么是Lambda

    Lambda['læmdə]表达式是一个没有函数名的匿名函数,基于数学中的希腊字母λ演算得名。

    2. 语法格式

    2.1. 语法格式

    Lambda函数的语法定义为:[capture(parameters) mutable ->return_type { statement }

    1) capture

    捕获列表,可以为空,但[]是必须的不能省略,编译器需要根据它来判断是否为Lambda函数。这个是整个Lambda中相对新鲜和复杂的地方,后面专节介绍

    区别于普通函数,捕获列表的意义在于:Lambda可直接访问父作用域中捕获列表所指定的变量,普通函数或类成员函数除了参数和类成员外,是不能访问父作用域(如调用它的父函数)中其它变量的。。

    2) parameters

    参数列表,和普通的函数没什么两样,如果没有参数,写可以写成(),不同于[],空的()也可省略。

    3) mutable

    修饰符,默认Lambda函数为const函数。

    4) ->return_type

    函数返回类型,在无返回值,或返回值可以推导出的情况下,可以省略。

    5) statement

    函数体,和普通函数体没有什么不同,但是除了可以使用参数外,还可以使用capture中所指定的变量。

    2.2. 最简定义

    通过以上规则,显然可以发现最简的Lambda函数定义:[] {};,这是一个什么也不做的空Lambda函数。

    3. 应用示例

    // 编译:g++ -std=c++11 -g -o x x.cpp

    // 示例在g++ 4.8.2上编译通过

    #include <stdio.h>

    int main()

    {

        int boys = 4;  // 男生人数

        int girls = 3; // 女生人数

        

        // 计算男生和女生总人数,

        // 这里必须用上C++11新定义的auto,

        // total_child类似于指向函数的指针了,并带两个int类型的参数

        auto total_child = [](int x, int y) -> int

        {

            return x + y;

        };

        

        // 调用

        int x = total_child(girls, boys);

        printf("%d ", x);

        

        return 0;

    }

    4. capture列表

    4.1. 基本形式

    这个是C++11 Lambda中非常有趣的地方,使用[]标识,有如下几种形式:

    1) [var表示以值传递方式捕获变量var

    2) [=表示以值传递方式捕获父作用域的所有变量,包括this

    3) [&var表示以引用传递方式捕获变量var

    4) [&表示以引用传递方式捕获父作用域的所有变量,包括this

    5) [this表示以值传递方式捕获this

    除以上5种基本形式化,还支持组合,如:

    1) [=, &a&b表示以引用传递方式捕获变量a和变量b,以值传递方式捕获父作用域的其它所有变量

    2) [&athis表示以值传递方式捕获父作用域的变量athis,以引用传递方式捕获其它所有变量

    4.2. 注意事项

    在上一节,可以看到捕获的几种基本形式,可以组合同时使用,但这里有个约束:不允许重复传递,比如:

    1) [=, a由于=表示以值传递方式捕获所有父作用域的变量,a就和它重复了,所以产生了语法错误

    2) [&&this同理,&this也重复了,同样是语法错误。

    5. 对比仿函数

    在C++中,仿函数就是用一个类来模仿含糊,虽然用得不多,但有时却需要它,比如自定义map的比较函数等场合。下面是一个仿函数示例:

    // 编译:g++ -std=c++11 -g -o y y.cpp

    // 示例在g++ 4.8.2上编译通过

    #include <stdio.h>

    // 定义一个仿函数

    class functor

    {

    public:

        // 仿函数的特点就是重载了类的()操作符

        int operator ()(int x, int y) const

        {

            return x + y;

        }

    };

    int main()

    {

        int boys = 4;

        int girls = 3;

        

        // 使用仿函数

        functor total_child;

        int x = total_child(girls, boys);

        printf("%d ", x);

        

        return 0;

    }

    由于仿函数是借助classstruct来实现的,因此它可以有类成员,仿函数被广泛的应用在STL的实现当中,它和Lambda函数相似,但要复杂一点。

    6. 对比函数指针

    Lambda函数并非函数指针,在C++11标准中将它定义为闭包(Closure)的类,每个Lambda会产生一个闭包类型的临时对象(右值)。

    虽然如此,但C++11标准允许Lambda表达式向函数指针的转换,前提是Lambda函数没有捕获任何变量,而且函数指针的原型必须和Lambda函数有相同的调用方式。

    7. LamdbaSTL

    Lamdba函数和STL中的for_each结合,是最典型的应用场景,它相比其它方式都显得更为简约:

    // 编译:g++ -std=c++11 -g -o z z.cpp

    // 示例在g++ 4.8.2上编译通过

    #include <algorithm>

    #include <stdio.h>

    #include <vector>

    using namespace std;

    void print(int i)

    {

        printf("%d ", i);

    }

    int main()

    {

        vector<int> nums;

        nums.push_back(2);

        nums.push_back(0);

        nums.push_back(1);

        nums.push_back(4);

        // 传统的for循环

        for (auto iter=nums.begin(); iter!=nums.end(); ++iter)

        {

            printf("%d ", *iter);

        }

        // 使用函数指针

        for_each(nums.begin(), nums.end(), print);

        // 使用Lamdba函数

        for_each(nums.begin(), nums.end(), [=](int i)

        {

            printf("%d ", i);

        });

        return 0;

    }

    8. 参考资料

    推荐进一步阅读:《深入理解C++11C++11新特性解析与应用》。

  • 相关阅读:
    beta冲刺总结-咸鱼
    咸鱼翻身beta冲刺博客集
    事后诸葛亮
    个人作业——软件产品案例分析
    Alpha冲刺博客集
    结对作业第二次
    项目需求分析(团队)
    第二次作业——个人项目实战
    软件工程实践第一次作业--准备
    beta冲刺总结
  • 原文地址:https://www.cnblogs.com/aquester/p/9891597.html
Copyright © 2011-2022 走看看