您的位置:首页 > 编程语言 > C语言/C++

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

2017-01-07 08:40 316 查看
我认为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函数只能捕捉到所在块的作用域及其父作用域中的自动变量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: