Re: [問題] 樣版設計 - 只接受特定幾種類別該怎設計?

看板C_and_CPP (C/C++)作者 (我要加入劍道社!)時間16年前 (2009/05/20 11:25), 編輯推噓1(109)
留言10則, 4人參與, 最新討論串2/3 (看更多)
話說,大家怎麼都把討論集中在「char 合不合理」 其實在我看來 template function 對「某些 type」無法作用 還算是滿常見的事 當然就這個 case 來說,是見人見智啦... ※ 引述《windincloud (雲淡風輕)》之銘言: : 今天我遇到一個樣版設計的問題~ : 問看看大家有沒有啥好想法? : 問題是這樣的~ : 我今天需要設計一個類別來計算數學問題(矩陣運算) : 當我寫 : template< class T > : void add(T** a,T** b,int X, int Y); ^ 多打了 : { : //matrix adding; : } : 但問題來了~ : T 可以是int float double : 但是char就應該不要吧~ : 那這樣要怎解決 template <class T> void add(T** a, T** b, int X, int Y) { // matrix adding } void add(char** a, char** b, int X, int Y); // No definition to produce link error 這方法就是 legnaleurc 提出的做法 當既存的 function 與引數的型別吻合時 C++ 會優先採用 function 而不會使用 function template 但我們只給宣告不給定義 所以會產生 link error 這作法有個缺點,就是 error message 會讓 user 搞不清楚狀況 yoco 有提出一個產生 compile time error 的方法 template <> void add(char** a, char** b, int X, int Y) { int matrix_element_should_not_be_char[0]; } 當使用者試圖以 char 作為 matrix element 的型別時 會產生如下的錯誤訊息: xxx.cc:13: error: ISO C++ forbids zero-size array ‘matrix_element_type_ should_not_be_char’ 注意這邊必須使用 function template specialization 若你像上面那樣直接定義一個一般的 function 那不管這個 char 版本的 add() 有沒有被使用者呼叫 都必須通過 compiler 的語法檢查,因此 compile 時會直接產生錯誤 但使用 function template 的情況下 只有在使用者呼叫 char 版本的 add() 時,compiler 才會試圖具現化這段程式 也只會在這時候產生 compile error 另外,gcc 的擴充語法支援大小為零的陣列,所以上述的人為錯誤並不會被測出 因此 compile 時要加上 -pedantic 這個參數才能正確處理這個技巧 : 且要是我想讓 vector< vector< T > >,list< list< T > >......等stl容器放入 : 那我該如何寫? : 總不會是一種寫一個吧~ : 那這樣就會失去template的意義的說~ 傳 iterator 即可 template <typename T, typename U> void add(T src, T src_end, U dst) { typedef typename iterator_traits<T>::value_type src_container; typedef typename iterator_traits<U>::value_type dst_container; while(src != src_end) { typename src_container::const_iterator si = src->begin(); typename dst_container::iterator di = dst->begin(); while(si != src->end()){ *di += *si; ++si; ++di; } ++src; ++dst; } } int main() { vector<vector<int> > a; list<list<int> > b; ... add(a.begin(), a.end(), b.begin()); } 但很不幸的,這樣一來 add 就不能用在 int** 或 double** 之類的型別 這邊有一個重點:操作 vector<vector<int> > 和操作 int** 的方法是不一樣的 vector<vector<int> > 是個容器,每個元素又是另一個 (有大小資訊的) 容器 但 int** 是個指標,指向另一個 (沒有大小資訊的) 指標 所以你很難寫一個 template 就兩者通吃 比較好的方法是你自己寫一個二維陣列的 class 而不要用 vector<vector<int> > 或 list<list<int> > 畢竟容器內再塞容器 效率上可能不太理想 另一個方法是寫兩個 template 一個給 int**、double** 這類型別使用 另一個則給 vector<vector<T> > 和 list<list<T> > 使用 雖然多寫了一個 template 但可以多處理許多「容器的容器」 : 我是有想過要typeinfo去處理~ typeinfo 是用在 run-time 取得型別資訊 template 則用在 compile-time 取得型別資訊 兩者是不同的角色 : 不過應該還有其他更聰明的方式處理~ : 有沒有那位大師有經驗的~ : 可以分享一下嘛? : 感謝~ -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 219.87.151.2

05/20 11:47, , 1F
不過他要的是白名單而不是黑名單...這才麻煩
05/20 11:47, 1F

05/20 11:50, , 2F
其實算一算~ 白名單黑名單都差不多多~ 所以我很頭大
05/20 11:50, 2F

05/20 11:51, , 3F
typeinfo 這個我是會放在函式中做檢查的機制啦~
05/20 11:51, 3F

05/20 11:51, , 4F
另外,參數應該也可以用type trait解決吧?
05/20 11:51, 4F

05/20 11:51, , 5F
型別錯誤 我會有個error msg出來這樣~
05/20 11:51, 5F

05/20 11:52, , 6F
typeinfo不可靠,而且是run-time才會執行
05/20 11:52, 6F

05/20 11:53, , 7F
意義上是"你可以這麼做,但是這是一種錯誤"
05/20 11:53, 7F

05/20 11:53, , 8F
而不是"你不可以這麼做"
05/20 11:53, 8F

05/20 12:00, , 9F
白名單很容易吧 就用 type trait
05/20 12:00, 9F

05/20 22:32, , 10F
也可以透過void來做到compiler time error
05/20 22:32, 10F
文章代碼(AID): #1A4tWTs6 (C_and_CPP)
文章代碼(AID): #1A4tWTs6 (C_and_CPP)