C++11之lambda表达式(影响面广)

我认为C++11给所有人带来最大的惊喜是引入了Lambda表达式!虽然第二早的高级语言LISP早就引入了这种编程范型,现代语言C#、PHP都提供了Lambda的支持,而最新的Java 8也提供了支持。

一、语法及示例代码:

首先给出Lambda语法定义:

[捕捉列表](参数列表) mutable/const->返回类型{ 函数体 }。

“捕捉列表”有两个作用,其一是告之编译器下面可能是Lambda表达式,其二是捕捉上下文变量供函数体使用。

“参数列表”与普通函数一样,并且在写法上会更简炼:如果没有参数,可以连同()全省略。

“mutable/const”为修饰符,默认情况下为const,mutable可取消常量性。

“返回类型”与一般函数相同,无返回类型时可以与->省略,在返回类型明确的情况下可由编译器推导出。

“函数体”就不用说了,与一般函数完全相同。

#include <iostream>
#include <cstdlib>

using namespace std;

int main()
{
    []{};    // 这可是最简单的Lambda函数
    int x=1, y=2;

    // [=]以值的方式捕获所有变量

    auto lambda1 = [=] { cout << x << '\t' << y << endl; };
    lambda1();

    // [&]以引用的方式捕获所有变量
    auto lambda2 = [&] { y += x; };
    lambda2();

    cout << x << '\t' << y << endl;

   // x以值y以引用的方式捕获,传入整型参数参与计算,再看函数体是否对x,y产生影响
    auto lambda3 = [x, &y](int i) mutable { x += i; y += i; };
    lambda3(10);
    cout << x << '\t' << y << endl;

   // 具有返回值的lambda函数
    auto lambda4 = [=]()->int { return x+y;};
    cout << lambda4() << endl;

    return 1;
}


二、Lambda函数的应用

2.1、STL和Lambda函数

#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> allnums;
vector<int> largenums;

const int base = 100;

inline void SaveLargeNums(int i)
{
    if(i>=base)
    {
        largenums.push_back(i);
    }
}

// 基于范围的for循环
inline void Show(void)
{
    for(auto val: largenums)
    {
        cout << val << '\t';
    }
    cout << endl;
}
inline void Clear(void)
{
    largenums.clear();
}
// 仿函数实现
class LargeNums
{
    public:
        LargeNums(int bs): base(bs){}
        void operator()(int i) const
        {
            if(i>=base)
            {
                largenums.push_back(i);
            }
        }
    private:
        int base; 
};

// 无参数选取并显示
void SelectAndShow(void)
{
     // 普通for循环
    for(auto it=allnums.begin(); it<allnums.end(); ++it)
    {
        if(*it >= base)
        {
            largenums.push_back(*it);
        }
    }
    Show();
    Clear();

    // STL中的for_each结合函数指针
    for_each(allnums.begin(), allnums.end(), SaveLargeNums);
    Show();
    Clear();

    // STL中的for_each结合lambda函数
    for_each(allnums.begin(), allnums.end(), [=](int i){
      if(i>=base)
        {
            largenums.push_back(i);
        }
    });
    Show();
    Clear();
}

// 有参数选取并显示
void SelectAndShow(int bs)
{
     // 普通for循环
    for(auto it=allnums.begin(); it<allnums.end(); ++it)
    {
        if(*it >= bs)
        {
            largenums.push_back(*it);
        }
    }
    Show();
    Clear();

    // STL中的for_each结合函数指针
    /*
    for_each(allnums.begin(), allnums.end(), SaveLargeNums);
    Show();
    Clear();
    */
    // STL中的for_each结合仿函数
    for_each(allnums.begin(), allnums.end(), LargeNums(bs));
    Show();
    Clear();

    // STL中的for_each结合lambda函数
    for_each(allnums.begin(), allnums.end(), [=](int i){
        if(i>=bs)
        {
            largenums.push_back(i);
        }
    });
    Show();
    Clear();
    // 基于范围的for循环结合lambda函数
    for(int i: allnums)
    {
        auto lambda = [=]{
            if(i>=bs)
            {
                largenums.push_back(i);
            }
        };
        lambda();
    }
    Show();
  Clear();
}

int main()
{
    // 初始化
    for(int i=0; i<20; i++)
    {
        allnums.push_back(i*10);
    }
    // 无参数形式选取
    SelectAndShow();
    // 有参数形式选取
    SelectAndShow(150);

    return 1;
}

上面代码可以看出,与STL结合使用中,仿函数与Lambda函数可以匹敌,函数指针在以参数传递时无能为力!for_each比普通的for循环在效率、性能、可扩展性、可维护性方面都要更胜一筹!在不用参数传递时,函数指针不一定被编译器进行inline优化。Lambda函数天生被编译器内联化,在循环量多时,效率不言而喻!

2.2、仿函数与Lambda函数

#include <iostream>
#include <cstdlib>

using namespace std;

class Tax
{
    private:
        float rate;
        int base;
    public:
        Tax(float r, int b): rate(r), base(b){};
        float operator() (float money){ return (money - base)* rate;}
};

int main()
{
    float rateL = 0.08, rateM = 0.13, rateH = 0.5;
    int baseL = 10000, baseM = 25000, baseH = 40000;
    Tax low(rateL, baseL);
    Tax Mid(rateM, baseM);
    Tax Hig(rateH, baseH);
    // 仿函数实现
    cout << "tax over 1w " << low(15000) << endl;
    cout << "tax over 2.5w " << Mid(30000) << endl;
    cout << "tax over 4w " << Hig(42000) << endl;
    // Lambda函数实现
    auto Llow = [=](int salary){ return (salary - baseL)*rateL;};  
    auto Lmid = [=](int salary){ return (salary - baseM)*rateM;};
    auto Lhig = [=](int salary){ return (salary - baseH)*rateH;};  
    cout << "tax over 1w " << Llow(15000) << endl;
    cout << "tax over 2.5w " << Lmid(30000) << endl;
    cout << "tax over 4w " << Lhig(42000) << endl;

    return 1;
}

从上面代码可以看出,仿函数与Lambda可以说很相似!C++98中仿函数在STL广泛使用,C++11中用Lambda可以简化仿函数的使用!既然以前有仿函数为何C++11还要提供Lambda函数呢?因为Lambda函数逻辑清晰,且能独立完成相应的功能,以下的代码示例就显示出Lambda函数的优越性。

#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>

using namespace std;
const int N = 10;

vector<int> nums;

void Init(void)
{
    nums.clear();
    for(int i=0; i<N; ++i)
    {
        nums.push_back(i);
    }
}

void Show(void)
{
    for(int val: nums)
    {
        cout << val << '\t';
    }
    cout << endl;
}

void OneCondition(int val)
{
    // 传统的for循环
    for(vector<int>::iterator it = nums.begin(); it<nums.end(); ++it)
    {
        if(*it == val)
        {
            cout << "find the num in range! " << endl;
            break;
        }
    }
    Show();

    // 传统的STL方式,equal_to为内置仿函数
    if(( find_if(nums.begin(), nums.end(), bind2nd(equal_to<int>(), val))) != nums.end())
    {
        cout << "find the num in range!" << endl;
    }
    Show();

    // 使用Lambda函数
    if(( find_if(nums.begin(), nums.end(), [=](int i){ return i==val;} )) != nums.end())
    {
        cout << "find the num in range!" << endl;
    }
    Show();
}

void TwoCondition(int low, int high)
{
    // 传统的for循环
    for(vector<int>::iterator it = nums.begin(); it<nums.end(); ++it)
    {
        if(*it>low && *it<high)
        {
            cout << "find the num in range! " << endl;
            break;
        }
    }
    Show();

    // 传统的STL方式,除非使用boost库提供的compose2才能完成STL内置less/greater_equal仿函数
    /*
    if(( find_if(nums.begin(), nums.end(), compose2(logical_and<bool>(), 
        bind2nd(less<int>(), high),
        bind2nd(greater_equal<int>(), low)))) != nums.end())
    {
        cout << "find the same num!" << endl;
    }
    */

    // 使用Lambda函数
    if(( find_if(nums.begin(), nums.end(), [=](int i){ return (i>low && i<high);} )) != nums.end())
    {
        cout << "find the num in range!" << endl;
    }
    Show();
}

void Minus(const int val)
{
     // 传统的for循环
    for(vector<int>::iterator it = nums.begin(); it<nums.end(); ++it)
    {
        *it = *it - val;
    }
    Show();

     // 传统的STL方式,equal_to为内置仿函数
    for_each(nums.begin(), nums.end(), bind2nd(minus<int>(), val));
    Show();

    transform(nums.begin(), nums.end(), nums.begin(), bind2nd(minus<int>(), val));
    Show();

    for_each(nums.begin(), nums.end(), [=](int &i){ i -= val;});
    Show();

}


void  Complication(int val)
{
    for_each(nums.begin(), nums.end(), [=](int &i){ 
        if(i<(-5))
        {
            i = abs(i);
        }
        else if(i<(-8))
        {
            i += val;
        }
        });


    Show();
}
int main()
{
    // 初始化
    Init();
    // 单条件
    OneCondition(2);
    // 两条件
    TwoCondition(4, 9); 
    // 减操作
    Minus(10);
    // 复杂操作
    Complication(10);
    return 1;
}


结果为:

find the num in range!
0       1       2       3       4       5       6       7       8       9
find the num in range!
0       1       2       3       4       5       6       7       8       9
find the num in range!
0       1       2       3       4       5       6       7       8       9
find the num in range!
0       1       2       3       4       5       6       7       8       9
find the num in range!
0       1       2       3       4       5       6       7       8       9
-10     -9      -8      -7      -6      -5      -4      -3      -2      -1
-10     -9      -8      -7      -6      -5      -4      -3      -2      -1
-20     -19     -18     -17     -16     -15     -14     -13     -12     -11
-30     -29     -28     -27     -26     -25     -24     -23     -22     -21

30      29      28      27      26      25      24      23      22      21

以上代码有三个看点:第一:在多条件匹配数据时,STL内嵌的仿函数必须借助于非标准库(如Boost库中的compose2)来完成相应的功能,代码晦涩难懂,没有Lambda函数直观!第二:在对容器数据进行改动时,for_each与内置仿函数minus<int>()已不能完成功能了,该仿函数只是将减的结果返回,没有对容器中数据作修改。只能借助于另一个STL函数:transform,内置仿函数minus<int>()返回的结果将写到第三个参数所给出的首地址当中。第三:在处理复杂运算时,STL库函数已无用武之地了,此时可以说Lambda函数完胜仿函数!另外Lambda函数可以是多参数,除非修改底层STL库,STL内置仿函数在参数上受限。


三、注意事项:

3.1、Lambda函数只能捕捉到所在块的作用域及其父作用域中的自动变量。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值