作者yoco315 (眠月)
看板C_and_CPP
標題Re: [問題] foreach實作
時間Thu Oct 7 02:28:02 2010
試考慮我有一個字串陣列,我要把內容印出來,很簡單。
string s[5] ;
for (size_t i = 0; i < 5; ++i) {
cout << s[i] << endl ;
}
若使用 std::for_each 實作的話的話,便是
std::for_each(s, s+5, cout << _1) ;
但是因為你的不是陣列,那就有點小麻煩,
還是可以作到,只是要用到類似 concept map 的 access idiom,
再加上一點點的 template meta-programming。
首先,讓我們寫一個 foreach class,
來作一次列印陣列的動作,只是這次改成是遞迴的方法。
template < int N > // 一般版本
struct foreach {
static void do() {
foreach<N-1>::do() ;
cout << s[N] << endl ;
}
} ;
template <> // 終止條件特化版本
struct foreach<-1> {
static void do() {} ;
} ;
好,但是這個 foreach 很爛,他只能用在陣列上面,
因為他沒辦法直接套用在我們需要的「異名」成員上,
但是沒關係,我們這個時候加入 access<>() 手法。
他之後就可以用在任何 class 上。
template < int N > // 加了這個
string access(s[]) { return s[N] ; }
template < int N > // 一般版本
struct foreach {
template < typename T >
static void do(T v) {
foreach<N-1>::do(v) ;
cout <<
access<N>(v) << endl ; // 改了這個
}
} ;
這個版本的 foreach 已經不在乎陣列不陣列了,
他只知道 access,而 access 到底會拿到什麼東西,看的是 access 裡面怎麼實作。
在這個例子裡面,access 會根據傳入的 N 去拿遞 N 個元素。
所以我們現在只要另外針對我們自己的 class 定義 access 的行為就好了。
只要把那些異名的 data member ,對應到不同特化的 access<>() 版本就可以了。
首先讓我們作個簡單的 class 來當作例子,
class C {
string a, b, c, d, e ;
} ;
然後定義這些 access map
template < int N >
string access(C c) ;
template <> string access<0>(C c) { return c.a ; }
template <> string access<1>(C c) { return c.b ; }
template <> string access<2>(C c) { return c.c ; }
template <> string access<3>(C c) { return c.d ; }
template <> string access<4>(C c) { return c.e ; }
嘿!這個時候 foreach 竟然就可以用在 C 上面啦~
太爽啦~撿到一百塊阿~佛舞美男幻阿~
C c ;
foreach::do<5>(c) ;
但是以上 code 完全沒有經過編譯跟測試,看看意思就好。
ㄎㄎ
--
To iterate is human, to recurse, divine.
遞迴只應天上有, 凡人該當用迴圈. L. Peter Deutsch
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 118.160.113.31
※ 編輯: yoco315 來自: 118.160.113.31 (10/07 02:29)
推 loveme00835:XDD 10/07 02:30
推 purpose:template真是深奧... 10/07 02:33
推 loveme00835:do ← 保留字喔 10/07 03:45
→ xatier: { ... } while(); 總是令人遺忘XD 10/07 07:13
推 ADF:這篇很故意喔... 10/07 08:46
推 heyshi:關鍵字筆記++謝謝y大 10/07 09:53
推 elfkiller:Push 10/07 10:42
→ yoco315:完全忘記,打這篇的時候,我還在想說:「奇怪,為什麼別人會把 10/07 10:51
→ yoco315:函數名稱取做大寫Do,幹麻不直接用 do 就好了,真笨 A_A」 10/07 10:52
→ yoco315:原來笨的是我 -___________-|| 10/07 10:53
→ yoco315:38頁開始有這種技法的高級應用qq 一個函數就可以用來求所 10/07 11:00
→ yoco315:有各種種類的point class的 distance.. 不管是 double[2] 10/07 11:02
→ yoco315:還是 wxPoint, 還是啥你自己定義的 class, double x, y ; 10/07 11:02
→ yoco315:而且各種維度, 2D, 3D.. 還是三小D 都可以一個函數做掉 10/07 11:03
推 nowar100:這技巧真有趣 10/07 11:07
→ james732:每次看到template就會有一種"我根本不會C++"的感覺...XDD 10/07 11:12
推 purpose:同意超哥 10/07 11:16
推 legendmtg:推!! 10/07 12:00
推 BlazarArc:james真是太中肯了(淚推) 10/07 16:49
推 xatier:超哥中肯阿!! 10/07 17:11
推 goldie:好文章,非常深入~~~~~~~~推!!! 10/07 20:54
推 VictorTom:j大還只有感覺, 小弟我是根本不會XD 10/07 23:27
推 hilorrk:我再也沒臉來C++板了 10/08 00:02
推 loveme00835:h 大...Orz 10/08 01:11