2010-04-28 101 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

相关问题