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

前端 未结 4 418
伪装坚强ぢ
伪装坚强ぢ 2021-01-03 07:14

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          


        
相关标签:
4条回答
  • 2021-01-03 08:01

    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.

    0 讨论(0)
  • 2021-01-03 08:04

    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.

    0 讨论(0)
  • 2021-01-03 08:15

    its not possible to know the variable type at compile time.

    0 讨论(0)
  • 2021-01-03 08:18

    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 >();
    }
    
    0 讨论(0)
提交回复
热议问题