最近看了 sicp 5.2 的 recusive + callback 的 scheme 寫法,
弄懂之後寫了個 c++ 的版本。
有興趣的朋友參考看看。
想順便問問看, std::function 可以省下來嗎? 我直接傳遞
std::function 那個 lambda function, compile 不會過。
t.cpp
1 // ref:http://goo.gl/k5MgDG (
http://kheresy.wordpress.com/2010/05/27/c0x%a1Glambda-expression/ )
2 #include <vector>
3 #include <algorithm>
4 #include <iostream>
5 #include <string>
6 #include <typeinfo>
7 #include<functional>
8
9 using namespace std;
10
84 template<typename Func>
85 void extract(const string &str, Func receive)
86 {
87 if (str.length() == 0)
88 {
89 string e1, e2;
90 receive(e1, e2);
91 }
92 else
93 {
94 // ref:http://goo.gl/hgh1EI (
http://www.cnblogs.com/ttss/p/4100917.html )
95 // std::function<int(int ,int)>func=add;
96 // <int(int,int)>是例化模板,表示返回值int,函2,(int,int),
97 // 即int(*pfunc)(int ,int )型的函
98 std::function<void(const string&, const string&)> f1 = [&](const
string &n, const string &s)
99 {
100 char next_ch = str[0];
101 string tmp_str;
102
103 tmp_str.push_back(next_ch);
104
105 #ifdef MORE_INFO
106 cout << "n: " << n << endl;
107 cout << "s: " << s << endl;
108 cout << "next_ch: " << next_ch << endl;
109 #endif
110
111 if ('0' <= next_ch && next_ch <= '9')
112 {
113 string new_str = n + tmp_str;
114 #ifdef MORE_INFO
115 cout << "new_str: " << new_str << endl;
116 cout << "===========" << endl;
117 #endif
118 receive(new_str, s);
119 }
120 else
121 {
122 string new_str = s + tmp_str;
123 #ifdef MORE_INFO
124 cout << "new_str: " << new_str << endl;
125 cout << "===========" << endl;
126 #endif
127 receive(n, new_str);
128 }
129 };
130
131 extract(str.substr(1), f1);
132 }
133 }
134
135 void assemble(string &str)
136 {
137 extract(str,
138 [] (const string &n, const string &s)
139 {
140 cout << n << endl;
141 cout << s << endl;
142 }
143 );
144 }
145
146 int main(int argc, char *argv[])
147 {
154 string str="x51ca2yz";
155 cout << str << endl;
157 assemble(str);
158 return 0;
159 }
一個 lambda function 的 type 應該怎麼描述? 為什麼需要把 type 寫出來, c++ 可不
是 scheme , 都不用宣告的, 所以不知道怎麼寫 lambda function 的type, 要怎麼傳
lambda function 給 function 當參數呢? 我想到邪惡萬用的 auto。
31 auto func = [] () { cout << "Hello world" << endl; }
可以, 不過帶有 capture-list 就不行了。
81 auto func = [&] () { cout << "Hello world" << endl; }
而且, 在 function 的 prototype 也不能寫 auto 來傳入 lambda function。
void f1(auto F);
fa(func);
這樣是不行的。
所以我想到是不是可以用 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 來傳遞。
最後修改函式的宣告, 使用 template 來宣告一個 template function, 這樣就可以接受
std::function 轉過的 function。
不過這樣有什麼好處嗎? 辛苦理解了這些新東西, 但他們能帶來更好的效益嗎? 花時間學
習划算嗎? 看看 scheme 和 c++ 的版本, c++ 寫來辛苦不少。c++11 加入了不少東西,
還有 c++14, 這些都是負擔很大的學習, 我的建議是: 取你想用的來學習, 不必有想把
c++ 全摸透的想法, 對於 template 我就很頭疼, 幾乎看不懂比較複雜的 template 程式
碼, 我願意學習難度高的 c++ 是因為她的彈性和效率, 可不是拿來折磨自己用的, 一旦
沒有了效率優勢, 我可能得找候補人選。
對於 std::function 的行為, 我實在好奇, 這是怎麼完成的呢? c++ 越來越神奇了。
我雖然搞懂了, 但是要我以這種思維來寫程式, 呃 ... 我功力還不夠。自從學了 c++11
後, 連自己都看不懂自己在寫什麼了。
scheme 和 recursive_call_back.cpp 的版本可以參考:
http://descent-incoming.blogspot.tw/2015/01/recursive-callback-function.html
( http://goo.gl/gClt7L )
// 本文使用 Blog2BBS 自動將Blog文章轉成縮址的BBS純文字 http://goo.gl/TZ4E17 //
blog 版本, 呃 ... 這次沒有 blog 版本 XD