I want to define an operator<< for all enums, to cout the value and print that it is an enum like开发者_开发百科 this:
code:
enum AnyEnum{A,B,C};
AnyEnum enm = A;
cout << enm <<endl;
output:
This is an enum which has a value equal to 0
I know a way of doing this with Boost library by using is_enum struct. But I don’t understand how it works. So that's why, in general, I am interested how to identify if the veriable is a class type, union type or an enum (in compile time).
Determining class types you could use the fact that member pointers exist
template<typename A, typename B>
struct issame { };
template<typename A>
struct issame<A, A> { typedef void type; };
template<typename> struct tovoid { typedef void type; };
template<typename T, typename = void>
struct isclass { static bool const value = false; };
template<typename C>
struct isclass<C, typename tovoid<int C::*>::type> {
static bool const value = true;
};
You cannot detect the difference of an union and a non-union class. At least I don't know how, and boost doesn't know either.
I think detecting enums could work by making sure T
isn't a class, function or integral type, and then trying to assign to an integral type. You could
template<typename E, typename = void>
struct isenum {
struct No { char x; };
struct Yes { No n1; No n2; };
struct nullsink {};
static No checkI(nullsink*); // accept null pointer constants
static Yes checkI(...);
static Yes checkE(int);
static No checkE(...);
static bool const value = (sizeof(checkI(E())) == sizeof(Yes)) &&
(sizeof(checkE(E())) == sizeof(Yes));
};
// class
template<typename E>
struct isenum<E, typename tovoid<int E::*>::type> {
static bool const value = false;
};
// reference
template<typename R>
struct isenum<R&, void> {
static bool const value = false;
};
// function (FuntionType() will error out).
template<typename F>
struct isenum<F, typename issame<void(F), void(F*)>::type> {
static bool const value = false;
};
// array (ArrayType() will error out)
template<typename E>
struct isenum<E[], void> {
static bool const value = false;
};
template<typename E, int N>
struct isenum<E[N], void> {
static bool const value = false;
};
Quick & dirty test (works on GCC/clang/comeau):
enum A { };
struct B { };
typedef int &C;
typedef void D();
typedef int E;
typedef long F;
typedef int const G;
typedef int H[1];
template<typename T, bool E>
struct confirm { typedef char x[(T::value == E) ? 1 : -1]; };
int main() {
confirm< isenum<A>, true >();
confirm< isenum<B>, false >();
confirm< isenum<C>, false >();
confirm< isenum<D>, false >();
confirm< isenum<E>, false >();
confirm< isenum<F>, false >();
confirm< isenum<G>, false >();
confirm< isenum<H>, false >();
}
I am interested how to identify if the veriable is a class type, union type or an enum (in compile time).
boost::type_traits
Even C++ TR1 has got a <type_traits>
header to support that functionality. In C++0x everything's gonna be a lot better.
For example the following machinery makes use of SFINAE to check whether the argument passed is a class type:
template<typename T>struct Check_If_T_Is_Class_Type
{
template<typename C> static char func (char C::*p);
template<typename C> static long func (...);
enum{val = CHECKER(func,Check_If_T_Is_Class_Type)};
};
The MACRO CHECKER
is
#define CHECKER(func_name,class_name) \
sizeof(class_name<T>::template func_name<T>(0)) == 1
To understand how type_traits work you need to have some basic knowledge of templates including template metaprogramming and SFINAE.
This is usually done with compiler hooks. The compiler has special functions that "fill" the template with the apropriate value (at least in C++0x where type_traits has been standardized).
For instance the is_pod
trait uses the __is_pod
compiler hook under VC 10 to get the apropriate information.
its not possible to know the variable type at compile time.
精彩评论