• (原创)C++11改进我们的程序之简化我们的程序(六)


      这次要讲的内容是:c++11中的lamda表达式。

      lamda表达式是我最喜欢的一个c++11特性之一,在我的代码中随处可见它的身影,其实在c#3.5中就引入了lamda,java中至今还没引入,要等明年的java8中才有lamda表达式,lamda来源于函数式编程的概念,也是现代编程语言的一个特点。c++11这次终于把lamda加进来了。也许有人要问,lamda有什么好处,为什么要加到c++中来?lamda表达式有这些优点:

    • 声明式编程风格:就地匿名定义你的目标函数或函数对象,不需要额外的写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
    • 简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
    • 在需要的时间和地点实现谓词,使我们的程序更灵活。

      lamda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。lamda表达式的语法形式:

    [ capture ] ( params ) -> ret { body }    
    如果没有返回值也没有参数,可以这样简写:
    [](){ body }或者[]{ body }
    [] (int x) -> { return x; }
    
    auto fun = [](){cout<<"test"}
    fun();

      lamda表达式可以截取一定范围内的变量:

    [] 不截取任何变量
    [&} 截取外部作用域中所有变量,并作为引用在函数体中使用
    [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
    [=, &foo]   截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
    [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
    [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。截取this的目的是可以在lamda中使用当前类的成员函数和成员变量。

    声明式编程风格,简洁的代码

      就地定义匿名函数,不再需要定义函数对象,大大简化了标准库算法的调用。比如c++11之前我们要调用for_each函数将vector中偶数打印出来,可能要这样写:

    struct CountEven
    {
    CountEven(int& count) : m_count(count)
    {
    }
    
    void operator()(int val)
    {
    if(val/2==0)
    {
    m_count++;
    }
    }
    
    private:
    int m_count;
    };
    
    int evenCount=0;
    for_each(v.begin(),v.end(),CountEven(evenCount));
    cout<<"偶数有 "<<evenCount<<""<<endl;

    用lamda表达式写:

    for_each(v.begin(),v.end(), [&evenCount](const int& val)
    {
    if(val/2==0)
    {
    evenCount++;
    }
    });

    不再需要定义函数对象,而且更简洁明了,可读性和维护性更好,开发效率也更高。

    在需要的时间和地点实现谓词,使我们的程序更灵活。

      上一篇博文中的那个计算集合中大于5小于10的函数用Lamda更简洁,之前用bind的写法:

    //查找大于10的元素的个数
    int count = count_if(coll.begin(), coll.end(), bind1st(less<int>(), 10));
    //查找小于10的元素的个数
    int count = count_if(coll.begin(), coll.end(), bind2nd(less<int>(), 10));
    
    //查找大于5小于10的元素的个数
    auto f = bind(std::logical_and<bool>(), bind(std::greater<int>(),_1,5), bind(std::less_equal<int>(),_1,10));
    int count = count_if(coll.begin(), coll.end(), f);

    用lamda的写法:

    //查找大于10的元素的个数
    int count = count_if(coll.begin(), coll.end(), [](int x){return x>10;});
    //查找小于10的元素的个数
    int count = count_if(coll.begin(), coll.end(), [](int x){return x<10;});
    //查找大于5小于10的元素的个数
    int count = count_if(coll.begin(), coll.end(), [](int x){return x>5&&x<10;});

    孰优孰劣,一眼便知,这就是生产力啊。


    lamda捕获参数

    stuct A
    {
    A():m_cout(0){}
    bool Add(int x, int y)
    {    
    return x>y;
    }
    
    void TestLamda()
    {
    vector<int> v = {1,2,3,4};
    sort(v.begin(), v.end(), [this](int x, int y){return Add(x,y);}); //调用成员函数,需要捕获this才可以
    
    int z = 4;
    sort(v.begin(), v.end(), [this,z](int x, int y) //z按值捕获
    {
    m_count = 4; //给成员变量赋值
    return Add(x,y);
    }); //调用成员函数,需要捕获this才可以
    
    sort(v.begin(), v.end(), [this,&z](int x, int y) //z按引用捕获
    {
    z = count+3; //给z赋值
    return Add(x,y);
    });
    
    //以引用方式传递作用域内所有可见的局部变量(包括this)
    for_each(v.begin(), v.end(), [=](int x){cout<<z+x<<endl;});
    
    //以引用方式传递作用域内所有可见的局部变量(包括this)
    for_each(v.begin(), v.end(), [&](int x){z++; cout<<z+x<<endl;});
    
    //部分变量按引用传递
    for_each(v.begin(), v.end(), [this, &z](int x){z++; cout<<z+x<<endl;});
    }
    
    int m_cout;
    };

      lamda能捕获变量很有用,一些外面的参数可以根据需要按值或者引用传入闭包。我甚至觉得lamda表达式几乎可以取代function, 可以通过捕获对象并调用对象的成员函数的方式取代bind成员函数的方式。例如:
    用bind和function的写法:

    A a;
    auto f = std::bind(&A::Add, &a, std::placehoders::_1,std::placehoders::_2);
    int x = 1, y=2;
    auto ret = f(x, y);

    用lamda的写法:

    auto f = [&a](int x, int y){return a.Add(x, y);};
    auto ret = f(x, y);

      效果是一样的,代码还更简洁了。不过不能完全替代function的原因是lamda表达式不能作为成员变量,还有有些标准库的和boost的方法不支持lamda,还需要function出场。

      c++11引入函数式编程的概念中的lamda,让我们的代码更简洁,更灵活,也更强大,并提高了开发效率,提高了可维护性。再次说一声lamada真是个好东西!

      c++11 boost技术交流群:296561497,欢迎大家来交流技术。

  • 相关阅读:
    Microsoft Visual Studio 2005中使用水晶报表
    net的辅助工具列表
    基于.net开发平台项目案例集锦
    一个蛮不错的图形绘制控件 dotnetCHARTING
    统计图控件dotnetCharting和ZedGraph比较
    c#获取真实IP和代理IP
    虚拟主机比较安全设置
    正则表达式 大杂烩
    【转载】说说大型高并发高负载网站的系统架构
    使用.NET实现断点续传
  • 原文地址:https://www.cnblogs.com/qicosmos/p/3304471.html
Copyright © 2020-2023  润新知