In < Modern C++ Design >,it introduces a way to check if a type fundamental type by introducing the so called type list. but what if I don't want to include so many loki co开发者_运维问答de and just want a simple function to implement that? What is the simplest way to do that?
don't re-invent the wheel use boost::type_traits
http://www.boost.org/doc/libs/1_42_0/libs/type_traits/doc/html/index.html
You can use template specialization to get what you want.
// 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);
}
In this code, if you pass in a type such as int
or char
, the compiler will use the specialization of IsFundamentalType
(given that you've defined the specializations for all fundamental types). Otherwise, the compiler will use the general template, as it is the case for the NonFundamentalType
class. The important thing is that the specialized ones have a result
member defined as true
, while the general template also has a result
member defined as false
. You can then use the result
member for the if
statement. Optimizing compilers should be able to elide the if
statement seeing that the expression reduces to a constant true/false value, so doing something like this should not impose a runtime penalty.
The simplest way is to create a type-traits object. Basically, you create an object (let's call it is_fundamental<T>) that is parameterized by the type and that inherits from boost::type_traits::no_type by default; then you specialize the object on all the fundamental types, making that specialization inherit from boost::type_traits::yes_type. So then you can use is_fundamental<T>::value as a boolean which will tell you if the type T is or is not a fundamental type. In most cases, you really don't need to know if a type is or is not fundamental, and when you do, it almost always involves templates, anyway, so might as well do it that way.
I should also point out that Boost already defines boost::type_traits::is_fundamental which does what you want. You can see in is_fundamental.hpp that they define it in terms of their other type-traits objects; a type is fundamental if it is a builtin arithmetic type or if it is the type "void" (which is also considered to be fundamental). Trying to figure things out from Boost can be kind of confusing but a simplification is:
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
That is essentially what it takes to create such a type-traits object. Note that one can maliciously specialize the type-trait to be true for a non-fundamental type, although that is the case for most things, anyway.
You can then use the above to create a more function-looking thing. For example, using the boost::type_traits::is_fundamental class, you could create the following:
template<typename T>
bool isFundametal(const T&)
{
return boost::type_traits::is_fundamental<T>::value;
}
Because the template specialization can be deduced from the parameters, you can invoke this isFundamental function without explicitly specifying the type. For example, if you write isFundamental(5) it will implicitly invoke isFundamental<int>(5), which will return true. Note, though, that if you create such a function, it won't allow you to test for void. You could create a function that took no parameters for such a case, but then the type wouldn't be deduced, and so it would be no prettier than simply using boost::type_traits::is_fundamenta<T>::value, and so one might as well just use it in that case.
精彩评论