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 <algorithm>
#include <cmath>
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 表達式規範

這裏寫圖片描述
其中(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 <vector>
#include "iostream"
#include <algorithm>
#include <functional>
//由淺到深,循序漸進的感受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 <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <ctime>

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章