看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《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 的部份... -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.229.105.244 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1421671811.A.EAF.html
descent: 感謝指證, 我描述有錯 01/20 09:40
lc85301: 高手 01/22 01:13