iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
1
Software Development

山姆大叔談 C++:從歷史談起,再給個定義—Modern C++ 解惑系列 第 15

DAY 14:Lambda,卷四:好東西也要用得恰到好處

  • 分享至 

  • xImage
  •  

這是第四篇,也是最後一篇談 Lambda。Lambda 之所以耐談,是因為好用;Lambda 之所以要多談,是因為容易誤用。開發者(我也在其中)常犯的毛病之一—手上有榔頭,看什麼都像是像釘子。好像全世界的問題都可以用同一個方法處理,這,當然是錯的。

實務遠比紙上談兵複雜,是否使用 Lambda,怎麼使用,請審慎評估。

Lambda 在 C++11 首現身,三年後的 C++14 又做了些許強化。其中,較為有用的是 Generic Lambda,以及 Initialized lambda capture(init-capture)。

Generic Lambda

考慮以下程式碼:

std::vector<int> vi = {1, 2, 3, 4, 5, 6};

auto sum = std::accumulate(begin(vi), end(vi),
                            0,
                            [](int v1, int v2)                           
                            {
                                return value > 4;
                            });

上述的 Lambda 只支援 std::vector<int> ,若容器型別為 std::vector<double> ,但邏輯不變,則另寫一個版本似乎有些「過意不去」。所幸,C++ Generic 的特性,在 C++14 時,加入了 Generic Lambda。上述程式碼改寫如下:

std::vector<double> vi = {1.0, 2.2, 3.4, 4.2, 5/2, 6/9};

auto sum = std::accumulate(begin(vi), end(vi),
                            0,
                            [](auto v1, auto v2) // Use 'auto' instead of type
                            {
                                return value > 4;
                            });

Initialized lambda capture

關於 Lambda,這裡有一篇優質文章,一步步拆解 C++ Lambda 的用法,非常推薦閱讀。

先前用到 Lambda Capture Clause 時,總是「抓」已經存在的變數,C++14 加入了 Initialized lambda capture,讓我們在 Lambda 內部使用被抓進來的對象前,做一些手腳。

std::vector<int> vi = {10, 20, 30, 40, 50};
const int kTarget = 3;

auto it = std::find_if(begin(vi), end(vi),
                       [target = kTarget * 10](auto value)
                       {
                           return target == value;
                       });

上述 target 的值為 30。有了 [id = expression] 的用法,Lambda 的應用場景更廣了。

雖然還沒談到 std::move,Lambda 遇到 std::unique_ptr 時,有一個用法很重要:

{
    std::vector<std::string> owners = {"COCO", "50", "1Shit"};
    auto owner = std::make_unique<std::string>("1Shit");
    
    auto the1shit = std::find(begin(owners), end(owners),
                              [the_one = std::move(owner)](auto o)
                              {
                                  return *the_one.get() == o;
                              });                              
}

留意我們在 Capture Clause 裡先「移動」 ownerthe_one,然後再給 Lambda 內部使用。(後面會有專篇介紹 std::move),這麼做就不用擔心 owner 離開 Scope 後被清掉,因為其擁有權已經轉移至 the_one


上一篇
DAY 13:Lambda,卷三:Capture By-reference
下一篇
DAY 15:好用的小功能
系列文
山姆大叔談 C++:從歷史談起,再給個定義—Modern C++ 解惑26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
vincentlee1481
iT邦新手 5 級 ‧ 2019-09-20 23:30:21

Lambda 遇到 std::unique std::unique_ptr

修改囉,感謝訂正。

我要留言

立即登入留言