工作中遇到一個問題,我有一個容器,裝着各式各樣的對象的指針,需要把擁有dump方法的指針內容dump出去,而對於沒有dump方法的對象,直接忽略。
首先想到的是給每個對象提供一個查詢操作,從而得知是否擁有dump方法。顯然這個方法不能讓人滿意,需要更改大量的class實現。C++如果我能自動判斷某個類型是否擁有某方法,這個問題可以完美的解決,因爲是否含有某方法編譯期已經確定了,所以是有可能通過一些技巧來實現這個功能的。
查閱了大量的模板偏特化,匹配失敗不是錯誤,終於找到了Mr.Right:
廢話不多說,貼代碼:
www.huaqiangu6.com
檢測是否有定義 void hello():
點擊(此處)摺疊或打開
template<typename T>
struct has_hello{
template<typename U, void (U::*)()> struct HELPS;
template<typename U> static char Test(HELPS<U, &U::hello>*);
template<typename U> static int Test(...);
const static bool Has = sizeof(Test<T>(0)) == sizeof(char);
}
測試:
點擊(此處)摺疊或打開
struct A
{
void hello(){
cout<<"A is Hello."<<endl;
}
int x;
};
int main()
{
cout<<"A has hello? "<<has_hello<A>::Has<<endl;
}
has_hello 能編譯通過,而且能工作!!!
解釋:
template<typename U> static int Test(...); 能匹配所有的類型U
template<typename U, void (U::*)()> struct HELPS; 當Type U有hello,且hello的類型爲 void (U::*)()時,模板HELPS<U, &U::hello>能正確匹配,否則模板無法匹配
Test<T>(0) 優先匹配 HELPS<U, &U::hello> 因爲template<typename U> static char Test(HELPS<U, &U::hello>*) 是一個特化
sizeof操作符不需要計算表達式的值,是一個編譯期的操作,定義指針類型可以只有聲明沒有定義
所以HELPS和Test都不需要實現,僅有聲明就可以通過編譯
巧妙的探測了自定義類型A是否含有void U::hello() 方法。