简体   繁体   中英

How to know if the argument that is passed to the function is a class, union or enum in c++?

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.

它不可能在编译时知道变量类型。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM