#include <iostream>

struct true_type
{
	enum {value = 1};
};

struct false_type
{
	enum {value = 0};	
};

template<typename T>
struct is_integer_impl : false_type {};

#define DECLARE_INTEGER(T) \
template<> \
struct is_integer_impl<T> : true_type {}

DECLARE_INTEGER(char);
DECLARE_INTEGER(unsigned char);
DECLARE_INTEGER(signed char);
DECLARE_INTEGER(unsigned short);
DECLARE_INTEGER(signed short);
DECLARE_INTEGER(unsigned int);
DECLARE_INTEGER(signed int);
DECLARE_INTEGER(unsigned long);
DECLARE_INTEGER(signed long);

template<typename T>
struct is_integer : is_integer_impl<T> {};

template<typename T>
struct is_class
{
	typedef char yes;
	typedef int no;
	
	template<class U>
	static yes doCheck(void (U::*)());
	template<class U>
	static no doCheck(...);
	
	enum {value = (sizeof(doCheck<T>(0)) == sizeof(yes))};
};

template<typename T>
struct is_enum
{
	enum {value = !is_integer<T>::value && !is_class<T>::value};
};

enum TestEnum
{
	Item1,
	Item2
};

struct TestStruct
{
	
};

union TestUnion
{
};

int main() 
{
	std::cout << is_integer<int>::value << std::endl;
	std::cout << is_enum<int>::value << std::endl;
	std::cout << is_class<int>::value << std::endl;
	std::cout << std::endl;
	std::cout << is_integer<TestStruct>::value << std::endl;
	std::cout << is_enum<TestStruct>::value << std::endl;
	std::cout << is_class<TestStruct>::value << std::endl;
	std::cout << std::endl;
	std::cout << is_integer<TestEnum>::value << std::endl;
	std::cout << is_enum<TestEnum>::value << std::endl;
	std::cout << is_class<TestEnum>::value << std::endl;
	std::cout << std::endl;
	std::cout << is_integer<TestUnion>::value << std::endl;
	std::cout << is_enum<TestUnion>::value << std::endl;
	std::cout << is_class<TestUnion>::value << std::endl;

	return 0;
}