• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Benjamin

            靜以修身,儉以養德,非澹薄無以明志,非寧靜無以致遠。
            隨筆 - 397, 文章 - 0, 評論 - 196, 引用 - 0
            數據加載中……

            c++和closure(閉包)

            一、定義: 是帶有上下文的函數。說白了,就是有狀態的函數。必須有上下文才能使用。
            函數, 帶上了狀態, 就變成了閉包了. 什么叫 "帶上狀態" 呢? 意思是這個閉包有屬于自己的變量, 這些個變量的值是創建閉包的時候設置的, 并在調用閉包的時候, 可以訪問這些變量.
            函數是代碼, 狀態是一組變量 ,將代碼和一組變量捆綁 (bind) , 就形成了閉包 ,內部包含 static 變量的函數, 不是閉包, 因為這個 static 變量不能捆綁. 你不能捆綁不同的 static 變量. 這個在編譯的時候已經確定了.
            二、c++實現閉包的方法:
            1、重載 operator() 例子
            class MyFunctor { public: MyFunctor(float f) : round(f) {} int operator()(float f) { return f + round; } private: float round; }; float round = 0.5; MyFunctor f(round);

            2、std::bind
            int my_func(float f, float round) { return f + round; } float round = 0.5; std::function<int(float,float)> f = my_func;

            3、lambda表達式,語法形式如下: [函數對象參數] (操作符重載函數參數) mutable或exception聲明 -> 返回值類型 { …函數體…}
            [函數對象參數],例如[&,a,b]標識一個Lambda的開始,這部分必須存在,不能省略。函數對象參數是傳遞給編譯器自動生成的函數對象類的構造函數的。

            函數對象參數有以下形式:
            [ ] 空沒有使用任何函數對象參數。
            [=] 函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是值傳遞方式(相當于編譯器自動為我們按值傳遞了所有局部變量)。
            [&] 函數體內可以使用Lambda所在作用范圍內所有可見的局部變量(包括Lambda所在類的this),并且是引用傳遞方式(相當于編譯器自動為我們按引用傳遞了所有局部變量)。
            [this] 函數體內可以使用Lambda所在類中的成員變量。
            [a] 將a按值進行傳遞。按值進行傳遞時,函數體內不能修改傳遞進來的a的拷貝,因為默認情況下函數是const的。要修改傳遞進來的a的拷貝,可以添加mutable修飾符。
            [&a] 將a按引用進行傳遞。
            [a, &b] 將a按值進行傳遞,b按引用進行傳遞。
            [=,&a, &b] 除a和b按引用進行傳遞外,其他參數都按值進行傳遞。
            [&, a, b] 除a和b按值進行傳遞外,其他參數都按引用進行傳遞。

            (操作符重載函數參數),例如(int a,int &b)標識重載的()操作符的參數,沒有參數時,這部分可以省略。參數可以通過按值(如:(a,b))和按引用(如:(&a,&b))兩種方式進行傳遞
            mutable與exception聲明,例如 mutable throw(),可省略
            按值傳遞函數對象參數時,加上mutable修飾符后,可以修改按值傳遞進來的拷貝(注意是能修改拷貝,而不是值本身,如果沒有添加mutable,相當于對函數參數的增加了const修飾,無法修改參數)。exception聲明用于指定函數拋出的異常,如拋出整數類型的異常,可以使用throw(int)。

            示例:
            ->返回值類型,例如 ->int 表示返回 int類型
            標識函數返回值的類型,當返回值為void,或者函數體中只有一處return的地方(此時編譯器可以自動推斷出返回值類型)時,這部分可以省略。
            {函數體},例如{cout<<“abc”;},不可省略,可以為空

            // 無函數對象參數,輸出:1 2   {    for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; });   }
               
            // 以值方式傳遞作用域內所有可見的局部變量(包括this),輸出:11 12   {    int a = 10;    for_each(vctTemp.begin(), vctTemp.end(), [=](int v){ cout << v+a << endl; });   }   
             // 以引用方式傳遞作用域內所有可見的局部變量(包括this),輸出:11 13 12   {    int a = 10;    for_each(vctTemp.begin(), vctTemp.end(), [&](int v)mutable{ cout << v+a << endl; a++; });    cout << a << endl;   }   
             // 以值方式傳遞局部變量a,輸出:11 13 10   {    int a = 10;    for_each(vctTemp.begin(), vctTemp.end(), [a](int v)mutable{ cout << v+a << endl; a++; });    cout << a << endl;   }
               
            // 以引用方式傳遞局部變量a,輸出:11 13 12   {    int a = 10;    for_each(vctTemp.begin(), vctTemp.end(), [&a](int v){ cout << v+a << endl; a++; });    cout << a << endl;   }   
             // 傳遞this,輸出:21 22   {    for_each(vctTemp.begin(), vctTemp.end(), [this](int v){ cout << v+m_nData << endl; });   }    
            // 除b按引用傳遞外,其他均按值傳遞,輸出:11 12 17   {    int a = 10;    int b = 15;    for_each(vctTemp.begin(), vctTemp.end(), [=, &b](int v){ cout << v+a << endl; b++; });    cout << b << endl;   }

            int temp = 10;
            vector<int> ivec = {30, -10, -20, 50, 40 ,100, -50};
            std::sort(ivec.begin(), ivec.end(), [](const int &x, const int &y) {return abs(x) < abs(y);});
            std::for_each(ivec.begin(), ivec.end(), [&](int &x) { x += temp; cout << x << endl;});
            三、注意事項:
            比較上面三種方式,有一些細節需要注意:

            1. closure的狀態特指其運行的上下文。 closure將存貯它運行時需要的上下文,從而保證在closure創建時的上下文可以在closure運行時依然有效。

            比如round就是closure的上下文。保存上下文的這一特點通常被稱作“capture”或者是"bind"。 capture可以自己寫,比如MyFuctor f(round); 也可以用boost::bind。

            當然最方便的還是讓編譯器幫你自動完成。編譯器將自動識別closure用到的變量,然后創建一個匿名的類,將這個變量保存到匿名類的成員變量中。

            C++中有兩種capture方式,by value和by reference。寫法是[=]和[&]。

            需要注意的是,capture by reference是不會修改被capture變量的生命周期的,你要保證被capture的變量在closure運行時是有效的。

            這一點不像Java,Java中變量被capture的話,就變成被引用了,從而GC不會回收它。

            2. closure的類型是隱藏的,每次創建一個closure,編譯器都會創建一個新的類型。

            如果你想保存一個clousre時就不是那么直接,因為你不知道它的類型。這時那需要一些模板技巧,可參考boost::function的實現。

            簡單的方式是直接用std::function來保存。

            std::function<int(float)> closure;

            closure = [](float f) { return 0.0f };

            closure = [](float f) { return 1.0f };

            四、閉包(匿名函數)用處,可以是流程更清晰,易于理解,一般不能單獨使用,必須有上下文,閉包里處理的是上下文中的一些變量。一般情況下不能單獨使用
            auto Do=[&]()
            {

            }
            auto nextDo=[=](){
            }

            posted on 2018-05-27 18:17 Benjamin 閱讀(803) 評論(0)  編輯 收藏 引用 所屬分類: C/C++

            国产精品99久久久久久宅男小说| 久久久久无码国产精品不卡| 国产毛片欧美毛片久久久| 久久精品国产亚洲AV不卡| 无码人妻少妇久久中文字幕蜜桃 | 久久99国产综合精品| 香港aa三级久久三级| 久久免费视频1| 狠狠色丁香久久婷婷综| 欧美日韩精品久久免费| 国产精品久久一区二区三区 | 精品国产乱码久久久久久郑州公司| 久久这里只有精品首页| 国产成人无码精品久久久性色 | 国产成人久久精品一区二区三区| 97久久国产亚洲精品超碰热| 亚洲国产综合久久天堂| 久久美女网站免费| 久久精品人人做人人爽97| 色婷婷久久久SWAG精品| 国内精品久久久久久不卡影院| 亚洲乱码精品久久久久..| 久久久久久av无码免费看大片 | 久久伊人影视| 国产精品无码久久四虎| 一本久久久久久久| 99久久er这里只有精品18| 国产美女亚洲精品久久久综合| 欧美粉嫩小泬久久久久久久| 99久久精品无码一区二区毛片| 久久久噜噜噜久久中文福利| 久久中文字幕人妻熟av女| 无码任你躁久久久久久老妇App| 久久精品中文字幕第23页| 激情久久久久久久久久| 精品久久久久久无码国产| 久久精品视频91| 久久综合色区| 久久精品aⅴ无码中文字字幕不卡| 伊人久久国产免费观看视频| 亚洲国产日韩欧美综合久久|