代码之家  ›  专栏  ›  技术社区  ›  Fabio Ceconello

用SFIEAE检测C++中某一类型的POD

  •  4
  • Fabio Ceconello  · 技术社区  · 16 年前

    原来的标题是 VS2005 C++中SfAYAG缺陷的解决方法

    这是对sfinae的尝试性使用,使其与存在于tr1中的is-pod模板类等效(在vs2005中还没有tr1)。它应该有 价值 如果模板参数是pod类型(包括基元类型和由它们组成的结构),则成员为true;如果不是,则成员为false(与重要的构造函数类似)。

    template <typename T> class is_pod
    {
      public:
    
        typedef char Yes;
        typedef struct {char a[2];} No;
    
        template <typename C> static Yes test(int)
        {
          union {T validPodType;} u;
        }
        template <typename C> static No test(...)
        {
        }
        enum {value = (sizeof(test<T>(0)) == sizeof(Yes))};
    };
    
    class NonPOD
    {
      public:
        NonPod(const NonPod &);
        virtual ~NonPOD();
    };
    
    int main()
    {
      bool a = is_pod<char>::value;
      bool b = is_pod<NonPOD>::value;
      if (a) 
        printf("char is POD\n");
      if (b)
        printf("NonPOD is POD ?!?!?\n");
      return 0;
    }
    

    问题是,不仅vs 2005没有tr1,它不会关心上面的联合(当模板参数不是pod时,这不应该有效),所以a和b的值都为true。


    感谢您的回答。在仔细阅读了它们(和代码)之后,我意识到我试图做的是一个真正错误的方法。这个想法是将sfinae行为与模板的适应相结合。 芥子皮 (我在书中找到的) 不完美C++ 但也可以在其他地方找到。实际上,这需要一套非常特殊的sfinae规则,显然这不是标准定义的。毕竟,这并不是VS中的错误。

    3 回复  |  直到 16 年前
        1
  •  4
  •   jpalecek    16 年前

    你的方法最大的问题是你不能在这里做sfinae——sfinae只适用于参数类型和返回类型。

    但是,在标准中的所有sfinae情况中,没有一个适用于您的情况。他们是

    • 空数组、引用数组、函数数组或大小无效的数组
    • 不是类型的类型成员
    • 指向引用的指针、指向引用的引用、指向void的引用
    • 指向非类类型成员的指针
    • 模板值参数的转换无效
    • 带有void类型参数的函数类型
    • 常量/易失函数类型

    这可能就是为什么在Boost文档中有:

    没有任何帮助 从编译器来看,ispod永远不会 报告类或结构是 如果可能的话,这总是安全的。 次优的目前(2005年5月)仅限 MWCW 9和Visual C++ 8都有 必要的编译器-_intrinsics.

        2
  •  2
  •   MSN    16 年前

    这也不适用于VS2008,但我怀疑你也知道。sfinae用于推导模板参数的模板参数;即使您可以创建与另一个类型不兼容的类型(即联合不能使用非pod),您也不能真正推断出显示类型的构造函数的类型。

    事实上,VS2008使用编译器对特性的支持来实现 std::tr1::type_traits .

        3
  •  1
  •   Dean Michael    16 年前

    我不确定你在这里的方式,因为 is_pod<T>::test(...) 将匹配 is_pod<T>::test(0) 也是。如果使用不同的类型而不是“int”,可能会得到更好的匹配:

    template <typename T> class is_pod
    {
      struct my_special_type { };
      public:
        typedef char Yes;
        typedef struct {char a[2];} No;
    
        template <typename C> static Yes test(my_special_type)
        {
          union {T validPodType;} u;
        }
    
        template <typename C> static No test(...)
        {
        }
        enum {value = (sizeof(test<T>(my_special_type())) == sizeof(Yes))};
    };
    

    你可能还想看看 Boost.Enable_i f为您做您的sfinae——除非您试图实现自己的库或出于某种原因。