Re: [分享] c++11 lambda & std::function

作者: suhorng ( )   2015-01-19 20:50:08
※ 引述《descent (「雄辯是銀,沉默是金」)》之銘言:
: 最近看了 sicp 5.2 的 recusive + callback 的 scheme 寫法,
: 弄懂之後寫了個 c++ 的版本。
: 有興趣的朋友參考看看。
: 想順便問問看, std::function 可以省下來嗎? 我直接傳遞
: std::function 那個 lambda function, compile 不會過。
推 kwpn: 編譯過不了的問題,應該先簡化程式碼來查問題出在哪. 01/19 19:59
我覺得一般而言應該可以省下來才對(template type deduction 不會有問題),
但這裡又遞迴, 我懷疑是造成編譯不過的原因, 因為每次都會有個新的 type 出來,
又遞迴呼叫自己(一個 template function), 造成 instantiate 出一個新的函式,
結果新的函式中 lambda 的 type 又不一樣了.
一個演示這個現象的例子(編譯不過):
template<typename F>
void loop(F f) {
loop([](){});
}
這裡無論是把傳進來的參數手動標 type 或是把新的 lambda function 手動標 type
(例如 loop<function<void()>>([](){}); )都可以解決.
題外話是, polymorphic recursion type inference 是 undecidable.
(這裡的 polymorphic 是參數式多型)
: 一個 lambda function 的 type 應該怎麼描述? 為什麼需要把 type 寫出來, c++ 可不
: 是 scheme , 都不用宣告的, 所以不知道怎麼寫 lambda function 的type, 要怎麼傳
: lambda function 給 function 當參數呢? 我想到邪惡萬用的 auto。
: 31 auto func = [] () { cout << "Hello world" << endl; }
因為 C++ 的作法中, lambda 的 type 是 compiler 唯一生成的, 每個都不一樣,
沒有標準的方法可以算出來(n4296 5.1.2.3). 這跟一般函數式語言不一樣.
: 可以, 不過帶有 capture-list 就不行了。
: 81 auto func = [&] () { cout << "Hello world" << endl; }
這邊我其實不太懂@@ 這段程式裡可以用 auto 存
我懷疑是其他因素造成編譯不過
template<typename F>
int f(F g) {
return g() - 1;
}
int main(int argc, char **argv) {
auto x = [&]() { return argc; };
return f(x);
}
: 而且, 在 function 的 prototype 也不能寫 auto 來傳入 lambda function。
: void f1(auto F);
: fa(func);
: 這樣是不行的。
所以才像 extract 一樣用 template 來接 lambda. C++14 的 generic lambda
倒是可以放 auto...但也差不多只是 template 而已.
auto add = [](auto n, auto m) { return n + m; };
: 所以我想到是不是可以用 function pointer 的方式傳進去, L31 的那種型式可以, ex:
: void f1(void (*F)());
: fa(func);
: 這樣就可以了, 但我想傳入 L81 那種型式的 lambda function 該怎麼辦呢? 為什麼有
: capture-list 不能以 function pointer 傳入呢? 因為他需要把外面那層的變數存起來
: , 這不是 c++ function 應該有的樣子, 那 c++ 有什麼機制可以把東西存起來, 而且也
: 有像 funciton 的行為呢? 你一定馬上想到 function object, 這就是
: recursive_call_back.cpp 為什麼要用上 function object 的原因。
: 有著 capture-list 的 lambda function 有個很酷的名稱 - lexical closure, 中國翻
: 譯成「閉包」, 台灣我不知道翻譯成什麼? 這東西感覺起來是不是和 function object
: 很像, lexical closure 搞不懂, 用 function object 來聯想也許就容易懂了。
: 但是我不想傳 function object, 那個我已經做過了, 那這個東西的 type 要怎麼寫呢?
: c++11 標準程式庫知道這很讓我們傷腦筋, 提供了 std::function 來完成這樣的事情。
: 所以我出動了 std::function 來將 BB 轉成 function object, 就可以當作 lambda
: function 的 type 來傳遞。
話說 C++ 的 lambda 常常就是用 function object 來實作的...?
std::function 是多包了一層還順便把介面統一了, 包含其他可呼叫的東西
: 最後修改函式的宣告, 使用 template 來宣告一個 template function, 這樣就可以接受
: std::function 轉過的 function。
已經用 std::function 轉過的話, 可能不是很需要用 template 來接, 直接用
std::function 就好了, 就是
void extract(
const string &str,
std::function<void(const string&, const string&)> receive)
{
}
: 不過這樣有什麼好處嗎? 辛苦理解了這些新東西, 但他們能帶來更好的效益嗎? 花時間學
: 習划算嗎? 看看 scheme 和 c++ 的版本, c++ 寫來辛苦不少。c++11 加入了不少東西,
: 還有 c++14, 這些都是負擔很大的學習, 我的建議是: 取你想用的來學習, 不必有想把
: c++ 全摸透的想法, 對於 template 我就很頭疼, 幾乎看不懂比較複雜的 template 程式
: 碼, 我願意學習難度高的 c++ 是因為她的彈性和效率, 可不是拿來折磨自己用的, 一旦
: 沒有了效率優勢, 我可能得找候補人選。
: 對於 std::function 的行為, 我實在好奇, 這是怎麼完成的呢? c++ 越來越神奇了。
猜測應該就只是把傳進來的 function object/function pointer/whatever 存起來,
主要的問題是 type 的部份...
作者: descent (「雄辯是銀,沉默是金」)   2015-01-20 09:40:00
感謝指證, 我描述有錯
作者: lc85301 (pomelocandy)   2015-01-22 01:13:00
高手

Links booklink

Contact Us: admin [ a t ] ucptt.com