Lambda 運算式練習題 (Practice - Lambda Expressions)

Question 1 - 預設 by-reference 捕獲的懸空風險 [recall]

addDivisorFilter() 內以 [&](int value){ return value % divisor == 0; } 將 lambda 加入全域的 filters 容器,其中 divisor 是區域變數;函式返回後呼叫該 filter 會發生什麼事?

Question 2 - [=] 在 member function 內的真相 [recall]

Widget::addFilter() const 內以 [=](int value){ return value % divisor == 0; } 使用 data member divisor[=] 複製進 closure 的到底是什麼?

Question 3 - [=] 與 static 變數 [recall]

函式內宣告 static auto divisor = ...;,lambda 以 [=] 加入 filters 後函式每次結尾執行 ++divisor;已加入的 closure 行為會改變嗎?為什麼?

Question 4 - 修正 data member 的捕獲 [application]

請給出兩種修正 Widget::addFilter() const 的寫法(C++11 一種、C++14 一種),讓 closure 真正持有 divisor 的複本而非 this

Question 5 - 智慧指標救不了懸空的 this [analysis]

doSomeWork()std::make_unique<Widget>() 建立 pw,呼叫 pw->addFilter()(內部用 [=] 捕獲)後返回;全程只用智慧指標,為何 filters 內仍出現 dangling pointer?請追蹤完整過程。

Question 6 - init capture 兩側的 scope [recall]

auto func = [pw = std::move(pw)] { return pw->isValidated() && pw->isArchived(); }; 中,= 左右兩個 pw 分別是什麼、位於哪個 scope?

Question 7 - 為何叫 generalized lambda capture [recall]

init capture 為什麼又稱 generalized lambda capture?它能做到哪件 C++11 capture 做不到的事、又有什麼唯一做不到的事?

Question 8 - C++11 模擬 move capture [application]

你只有 C++11 編譯器,想把填好資料的 std::vector<double> data 「move 進 closure」;請用 std::bind 寫出模擬版,並說明 lambda 參數的宣告方式。

Question 9 - bind object 的儲存規則 [recall]

std::bind 收到 lvalue 引數與 rvalue 引數時分別如何存入 bind object?bind object 與其內含 closure 的生命週期關係為何?

Question 10 - generic lambda 的完美轉發 [recall]

auto f = [](auto&& x){ return funcforward<???>(x)); };??? 應填什麼?為何不能照慣例寫 std::forward<T>

Question 11 - decltype 給出 rvalue reference 為何仍正確 [analysis]

傳 rvalue 給 auto&& xdecltype(x) 產生 Widget&& 而非慣例的非參考型別 Widget;請由 std::forward 的實作推導為何 std::forward<Widget&&>std::forward<Widget> 結果相同。

Question 12 - std::bind 的引數求值時機 [recall]

std::bind(setAlarm, steady_clock::now() + 1h, _1, 30s) 想設定「呼叫後一小時響鈴」,錯在哪?如何修正?

Question 13 - C++11 僅存的 bind 用例 [recall]

Item 34 主張偏好 lambda,但承認 std::bind 在 C++11 有兩個合理用例;是哪兩個?C++14 分別被什麼取代?

Question 14 - 重載函式與 bind 的歧義 [application]

setAlarm 新增了四參數重載(多了 Volume)後,原本的 std::bind(setAlarm, ...) 無法編譯而 lambda 版照常運作;請解釋原因並寫出讓 bind 編譯的修法。