C++的模板其實是個挺糾結的東西,用的不好的話,編譯的一堆錯誤夠你調到崩潰,但要是用的好呢,又確實非常方便,我們來看看
一.獲取數組長度
比如
1 |
int arr[10]; |
怎麼獲取 arr 的長度呢?
最簡單的代碼:
1 |
uint32_t count = sizeof(arr) / sizeof(arr[0]); |
但是這樣也帶來一個問題,萬一是個新手程序員:
1 2 |
int *p = arr; uint32_t count = sizeof(p) / sizeof(p[0]); |
就有問題了……
那麼有沒有辦法,有一種安全的方法,當發現傳入的是指針的時候,自動編譯報錯呢?
有的,模板裏面可以推導出數組的長度。
所以我們可以使用如下代碼
1 2 |
template <typename T, size_t N> size_t arrarysize(T (&array)[N]) { return N; } |
這樣,當傳入指針的時候,編譯就會報錯了。
而同時你肯定也能看出,我們甚至能指定只能傳入數組長度爲固定某數字的數組了,怎麼做我就不用講了吧?
二.切片函數
python中的切片函數真是令人懷念,並且即使傳入的參數超過長度也不會崩潰,可是C++裏面則就會出現問題,所以通常我們要把一個容器的數據做切片時,代碼如下:
1 2 3 4 5 6 7 8 9 |
vector<int> src; vector<uint32_t> dst; uint32_t index; uint32_t count; vector<uint32_t>::iterator it_begin = src.begin() + index; vector<uint32_t>::iterator it_end = (it_begin + count) < src.end() ? (it_begin + count) : src.end(); dst.insert(dst.begin(), it_begin, it_end); |
注: 如果直接如下調用,會導致取到end()之後多餘的數據
1 |
dst.insert(dst.begin(), src.begin() + index, src.begin() + index + count) |
其實這代碼還是挺糾結,而且並不通用(各種類型的容器都要重複寫代碼),所以我們也可以用模板來優化一下,代碼如下:
1 2 3 4 5 6 7 8 9 10 |
template <typename T, typename P> int Cut2Part(T& src, uint32_t index, uint32_t count, P& dst) { typeof(src.begin()) it_begin = src.begin() + index; typeof(src.begin()) it_end = (it_begin + count) < src.end() ? (it_begin + count) : src.end(); dst.insert(dst.begin(), it_begin, it_end); return 0; } |
可以注意到代碼中使用了typeof,這也是C++挺好用的一個特性。
所以無論是什麼類型的容器,只要如下調用即可
1 2 3 |
vector<int> src; list<uint32_t> dst; Cut2Part(src, index, count, dst) |
三.獲取類名
當在使用模板,或者使用繼承關係的類時,我們經常需要在打印Log時清楚的知道到底是哪個類的實例在執行。
所以我們可以用這個函數:
1 |
typeid(obj).name() |
如果實在類實例內部:
1 |
typeid(*this).name() |
OK,需要介紹的內容就是這樣了~~
說句後話,python的確要比C++方便很多,但是在C++中經常會有這樣的情景:在經過長時間嘗試之後,“哇,原來這樣能實現!”其實也是很不錯的過程~比如之前的另一個宏定義:
1 2 3 4 |
#ifndef foreach #define foreach(container,it) \ for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it) #endif |