【问题标题】:How to know if the argument that is passed to the function is a class, union or enum in c++?如何知道传递给函数的参数是 C++ 中的类、联合还是枚举?
【发布时间】:2011-01-16 12:25:57
【问题描述】:

我想为所有枚举定义一个运算符

代码:

enum AnyEnum{A,B,C};
AnyEnum enm = A;
cout << enm <<endl;

输出:

This is an enum which has a value equal to 0

我知道一种通过使用 is_enum 结构来使用 Boost 库的方法。但我不明白它是如何工作的。所以这就是为什么,一般来说,我对如何识别可验证对象是类类型、联合类型还是枚举(在编译时)感兴趣。

【问题讨论】:

    标签: c++ boost enums template-meta-programming


    【解决方案1】:

    确定可以使用成员指针存在的事实的类类型

    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;
    };
    

    您无法检测联合和非联合类的区别。至少我不知道怎么做,boost也不知道。

    我认为检测枚举可以通过确保T 不是类、函数或整数类型,然后尝试分配给整数类型来工作。你可以

    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;
    };
    

    快速而肮脏的测试(适用于 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 >();
    }
    

    【讨论】:

    • (void) sizeof(x) 是什么意思? :-/
    • @Nawaz :它(转换为void)只是为了抑制返回值。 :)
    • @Prasoon : 呵呵..我一开始就是这么想的.. 但后来我想到既然是约翰内斯,也许他的意思是我不知道的其他东西。
    • @Nawaz @Prasoon 说了什么 :) 我已经简化了 main,所以它现在不再使用这些东西了。
    • 以前的东西看起来很怪异。你应该把它放在那里。:P
    【解决方案2】:

    我很感兴趣如何识别可验证对象是类类型、联合类型还是枚举(在编译时)。

    boost::type_traits

    即使C++ TR1 也有一个&lt;type_traits&gt; 标头来支持该功能。在 C++0x 中,一切都会好很多。

    例如,以下机器使用SFINAE 来检查传递的参数是否为类类型:

    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)};
    };
    

    CHECKER

    #define CHECKER(func_name,class_name) \
    sizeof(class_name<T>::template func_name<T>(0)) == 1
    

    要了解 type_traits 的工作原理,您需要具备一些模板的基本知识,包括 template metaprogramming 和 SFINAE。

    【讨论】:

    • 是的,我就是这个意思。请解释一下这个结构是如何工作的?例如 is_enum。
    • @Narek :您需要了解模板的工作原理以及与模板元编程和 SFINAE 相关的基础知识。
    • 好的,我对一些概念很熟悉。所以您的示例如何识别 T 是否是一个类?
    • @Narek :非类类型没有指向成员的指针。这应该会给出一些提示。
    • 除了第一个函数参数(char C::*p)外,几乎很清楚。如果我定义了一个这样的类怎么办:class Test{ int member_};作为模板 patam “T”,我使用“Test”,那么对于这种情况,“char C::*p”是什么?
    【解决方案3】:

    这通常通过编译器挂钩来完成。编译器具有使用适当值“填充”模板的特殊功能(至少在 type_traits 已标准化的 C++0x 中)。 例如is_pod trait 使用 VC 10 下的 __is_pod 编译器钩子来获取适当的信息。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2013-09-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-10
        • 2011-12-04
        • 2016-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多