2010-04-28 142 views
2

在<現代C++設計>,它引入了一種方法來檢查是否通過引入所謂的類型列表來檢查類型的基本類型。但是如果我不想包含這麼多的loki代碼並且只想要一個簡單的函數來實現呢?什麼是最簡單的方法來做到這一點?有沒有簡單的方法來檢查基本類型

回答

4

你可以使用模板專門化來得到你想要的。

// General template 
template<typename T> 
struct IsFundamentalType { enum { result = false }; }; 

// Template specializations for each fundamental type 
template<> 
struct IsFundamentalType<char> { enum { result = true }; }; 

template<> 
struct IsFundamentalType<int> { enum { result = true }; }; 

template<> 
struct IsFundamentalType<short> { enum { result = true }; }; 

template<> 
struct IsFundamentalType<float> { enum { result = true }; }; 

// And so on for other fundamental types ... 

class NonFundamentalType 
{ 
}; 

template<typename T> 
void DoSomething(const T& var) 
{ 
    if(IsFundamentalType<T>::result) 
    { 
     printf("I'm fundamental type!\n"); 
    } 
    else 
    { 
     printf("I'm not a fundamental type!\n"); 
    } 
} 

int main() 
{ 
    int i = 42; 
    char c = 42; 
    short s = 42; 
    float f = 42.0f; 
    NonFundamentalType nft; 
    DoSomething(i); 
    DoSomething(c); 
    DoSomething(s); 
    DoSomething(f); 
    DoSomething(nft); 
} 

在此代碼,如果你在一個類型傳遞,例如intchar,編譯器將使用的IsFundamentalType專業化(假設您已經定義了專業化的所有基本類型)。否則,編譯器將使用通用模板,因爲類是NonFundamentalType類。重要的是,專用模塊的result成員定義爲true,而通用模板也有一個result成員,定義爲false。然後,您可以使用result成員作爲if語句。優化編譯器應該能夠忽略if語句,看到表達式減少到一個常量的真/假值,所以做這樣的事情不應該強加運行時懲罰。

2

最簡單的方法是創建一個類型特徵對象。基本上,你創建一個對象(我們稱之爲is_fundamental <T>),該對象由類型參數化,並且默認從boost :: type_traits :: no_type繼承;那麼你在所有基本類型上專門化這個對象,使得這個專門化繼承自boost :: type_traits :: yes_type。那麼你可以使用is_fundamental <T> :: value作爲一個布爾值,它會告訴你T類型是否是基本類型。在大多數情況下,你確實不需要知道某個類型是否是基本類型,而當你這樣做時,它幾乎總是涉及到模板,不管怎樣,這樣做也可以。

我還應該指出,Boost已經定義了boost::type_traits::is_fundamental這是你想要的。你可以在is_fundamental.hpp中看到他們根據其他類型特徵對象來定義它;如果是內建的算術類型,或者類型是「無效」(也被認爲是基本的),則類型是基本的。試圖從升壓搞清楚這些事情可能是一種混亂,但簡化爲:

template<typename T, T VAL> struct constant_value 
{ 
    static const T value = VAL; 
}; 

typedef constant_value<bool,true> yes_type; 
typedef constant_value<bool,false> no_type; 

template<typename T> struct is_fundamental : public no_type{}; 

// Create a macro for convenience 
#define DECLARE_FUNDAMENTAL(X) \ 
    template<> struct is_fundamental<X> : public yes_type{} 

// Specialize for all fundamental types 
DECLARE_FUNDAMENTAL(void); 
DECLARE_FUNDAMENTAL(bool); 
DECLARE_FUNDAMENTAL(signed char); 
DECLARE_FUNDAMENTAL(unsigned char); 
// ... lots more similar specializations ... 
DECLARE_FUNDAMENTAL(wchar_t); 
DECLARE_FUNDAMENTAL(float); 
DECLARE_FUNDAMENTAL(double); 
DECLARE_FUNDAMENTAL(long double); 

// Prevent this macro from polluting everything else... 
#undef DECLARE_FUNDAMENTAL 

這實質上是如何才能創造這樣的類型traits對象。請注意,可以惡意地將類型特徵專門化爲非基本類型,儘管無論如何對於大多數情況都是如此。

然後,您可以使用上述來創建一個更具功能性的東西。例如,使用升壓:: type_traits :: is_fundamental類,你可以創建以下:

template<typename T> 
bool isFundametal(const T&) 
{ 
    return boost::type_traits::is_fundamental<T>::value; 
} 

由於模板專業化可以從參數可以推斷,你可以調用這個函數isFundamental沒有明確指定類型。例如,如果您編寫isFundamental(5),它將隱式調用isFundamental <int>(5),它將返回true。但是請注意,如果您創建了這樣一個函數,它將不允許您測試void。你可以創建一個沒有參數的函數,但是這個類型不會被推導出來,所以它不會比簡單地使用boost :: type_traits :: is_fundamenta <T> :: value等更漂亮不妨在這種情況下使用它。

5

不重新發明輪子使用的boost :: type_traits

http://www.boost.org/doc/libs/1_42_0/libs/type_traits/doc/html/index.html

+0

但是,被這意味着引進Boost庫?或只有一個頭文件? – 2010-04-29 00:38:12

+0

正確的方法是下載最新的boost,安裝它,編譯,然後在你的代碼中只包含需要的頭文件。你不應該將boost文件複製到你的項目中。 請注意,boost :: type_traits庫僅用於頭文件,您無需編譯即可使用它 – 2010-04-29 08:23:44

相關問題