C++实现Lambda表达式

C++实现Lambda表达式

4年过去了,还是程序媛小白。导师让看看关于Lambda算子的东西,才第一次知道函数式编程,lambda算子,艰难的进阶之路。记录一下学习历程。总结一下看过的资料。
原作:https://www.cnblogs.com/haippy/archive/2013/05/31/3111560.html
http://blog.csdn.net/u011437229/article/details/78696599

lambda表达式简介

“函数式编程”是一种“编程范式”,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
匿名函数是许多编程语言都支持的概念,有函数体,没有函数名。1958年,lisp首先采用匿名函数,匿名函数最常用的是作为回调函数的值。正因为有这样的需求,c++引入了lambda 函数,你可以在你的源码中内联一个lambda函数,这就使得创建快速的,一次性的函数变得简单了。例如,你可以把lambda函数可在参数中传递给std::sort函数。

#include 
#include 
void abssort(float* x, unsigned N) {
    std::sort(x, x + N,
        // Lambda expression begins
        [](float a, float b) {
            return std::abs(a) < std::abs(b);
        });
}

C++11 的 lambda 表达式规范

C++实现Lambda表达式_第1张图片
其中(1)是完整的Lambda表达式形式,
(2)const类型的lambda表达式,该类型的表达式不能改捕获(“capture”)列表中的值。
(3)省略了返回值类型的lambda表达式,但该表达式的返回类型可以按照一定规则推断出来:
如果lambda代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。
如果没有 return 语句,则类似 void f(…) 函数。
(4)省略了参数列表,类似于无参函数 f()。
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。

exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X, Y)。

attribute 用来声明属性。

另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:

[a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
[this] 以值的方式捕获 this 指针。
[&] 以引用的方式捕获所有的外部自动变量。
[=] 以值的方式捕获所有的外部自动变量。
[] 不捕获外部的任何变量。

代码实例

#include 
#include "iostream"
#include 
#include 
//由浅到深,循序渐进的感受lambda的神奇之处
void lambda_one() {
    std::cout << std::endl << "----------没有函数参数的lambda---------" << std::endl;
    auto fun = []() {};
    auto fun1 = []() { std::cout << "fun1" << std::endl; };
    fun1();

    std::cout << std::endl << "--------for_each中使用简单的lambda------" << std::endl;
    std::vector<int> v(3, 5);
    for_each(v.begin(), v.end(), [](int num) { std::cout << num << "\t"; });

    std::cout << std::endl << "---------设置lambda的返回值类型--------" << std::endl;
    std::cout << [](double a, double b) { return a + b; }(1.4, 2.5) << std::endl;
    std::cout << [](double a, double b) -> int { return a + b; }(1.4, 2.5) << std::endl;

    std::cout << std::endl << "---------lambda中的传值---------------" << std::endl;
    int x = 1;
    int y = 100;
    [=](double a, double b)mutable -> int {
        std::cout << "lambda:" << (x = 100) << "\t" << (y = 10) << std::endl;
        return a + b;
    }(1.4, 2.5);
    std::cout << "main:" << x << "\t" << y << std::endl;

    std::cout << std::endl << "---------lambda中的传引用--------------" << std::endl;
    [&x, &y](double a, double b) -> int {
        std::cout << "lambda:" << (x = 100) << "\t" << (y = 10) << std::endl;
        return a + b;
    }(1.4, 2.5);
    std::cout << "main:" << x << "\t" << y << std::endl;

    std::cout << std::endl << "-----------lambda中的传引用和引用传递------" << std::endl;
    //等号必须写在前面,或者也可以[x,&y].
    //=表示,除了&y,其他所有的外部变量都可以按照值传递进行访问。
    //注:不知道是否有人跟我一样,在这儿困惑了很久呢?按照道理来说,[=,&y]一个传值,一个传引用,那么x(以复制方式捕获的)在main输出结果应该是1,而不是100。找了一些资料,是这样解释的:
    //虽然按值捕获的变量值均补复制一份存储在lambda表达式变量中,修改他们也并不会真正影响到外部,但我们却仍然无法修改它们。
    //那么如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable。mutable表示非引用的值也可读可写,但不能返回 
    //需要注意:被mutable修饰的lambda表达式就算没有参数也要写明参数列表。
    //原因:lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。
    [=, &y](double a, double b) mutable -> int {
        std::cout << "lambda:" << (x = 100) << "\t" << (y = 10) << std::endl;
        return a + b;
    }(1.4, 2.5);
    std::cout << "main:" << x << "\t" << y << std::endl;
}

void lambda_two() {
    // sort 排序
    using namespace std;
    std::cout << std::endl << "-----------sort排序中使用lambda------" << std::endl;
    int a[8] = {6, 8, 3, 4, 9, 2, 7, 1};
    sort(begin(a), end(a), [](const int &a, const int &b) -> bool { return a < b; });
    for_each(begin(a), end(a), [](const int &num) { cout << num << "\t"; });
    cout << endl << "-----------------------------------------------" << endl;
}
void lambda_three() {
    // (lambda递归) 3个数返回最大的两个数的和
    using namespace std;
    function<int(int, int, int)> f = [&f](int a, int b, int c) -> int {
        if (a <= b && a <= c) {
            return b + c;
        }
        return f(b, c, a);
    };
    cout << f(4, 1, 6) << endl;

}

void lambda_four() {
    //判断数组中的偶数个数,两种写法
    std::vector<int> v = {1, 2, 3, 4, 5};
    int even_count = 0;
    int even_count_x = std::count_if(v.begin(), v.end(), [](int x){return x % 2 == 0;});
    std::for_each(v.begin(), v.end(), [&even_count](int val) {
        if (!(val & 1)) {
            ++even_count;
        }
    });
    std::cout << "method1:the number of even is " << even_count << std::endl;
    std::cout << "methods:the number of even is " << even_count_x << std::endl;
}

比较函数指针、函数符(functor)和Lambda函数

/**
 * @anchor xin
 * 功能描述:生成一个随机整数列表,并判断其中多少个整数克被3整除,多少个整数被13整除
 */

#include 
#include 
#include 
#include 
#include 

const unsigned long Size1 = 39L;
const unsigned long Size2 = 100 * Size1;
const unsigned long Size3 = 100 * Size2;

bool f3(int x) { return x % 3 == 0; };

bool f13(int x) { return x % 13 == 0; };

int main() {
    using namespace std;
    std::vector<int> numbers(Size1);

    std::srand(static_cast<unsigned int>(std::time(0)));
    std::generate(numbers.begin(), numbers.end(), std::rand);

    //using function pointers
    cout << "Samples size=" << Size1 << endl;
    auto count3 = std::count_if(numbers.begin(), numbers.end(), f3);
    cout << "Count of numbers divisible by 3:" << count3 << endl;
    auto count13 = std::count_if(numbers.begin(), numbers.end(), f13);
    cout << "Count of numbers divisible by 13:" << count13 << endl;

    //increase number of numbers
    numbers.resize(Size2);
    std::generate(numbers.begin(), numbers.end(), std::rand);
    cout << "Samples size=" << Size2 << endl;

    //using a functor
    class f_mod {
    private:
        int dv;
    public:
        f_mod(int d = 1) : dv(d) {};

        bool operator()(int x) { return x % dv == 0; }
    };

    count3 = std::count_if(numbers.begin(), numbers.end(), f_mod(3));
    cout << "Count of numbers divisible by 3:" << count3 << endl;
    count13 = std::count_if(numbers.begin(), numbers.end(), f_mod(13));
    cout << "Count of numbers divisible by 13:" << count13 << endl;

    //increase number of numbers again
    numbers.resize(Size3);
    std::generate(numbers.begin(), numbers.end(), std::rand);
    cout << "Samples size=" << Size3 << endl;

    //using lambda
    count3 = std::count_if(numbers.begin(), numbers.end(), [](int x) { return x % 3 == 0; });
    cout << "Count of numbers divisible by 3:" << count3 << endl;
    count3 = std::count_if(numbers.begin(), numbers.end(), [](int x) { return x % 13 == 0; });
    cout << "Count of numbers divisible by 13:" << count13 << endl;
    return 0;
}

你可能感兴趣的:(C++)