简体   繁体   English

使用 SFINAE 检测 C++ 中类型的 POD-ness

[英]Using SFINAE to detect POD-ness of a type in C++

The original title here was Workaround for SFINAE bug in VS2005 C++这里的原标题是VS2005 C++ 中 SFINAE 错误的解决方法

This is tentative use of SFINAE to make the equivalent for the is_pod template class that exists in TR1 (In VS2005 there's no TR1 yet).这是 SFINAE 的尝试性使用,以生成 TR1 中存在的 is_pod 模板类的等效项(在 VS2005 中还没有 TR1)。 It should have its value member true when the template parameter is a POD type (including primitive types and structs made of them) and false when it's not (like with non-trivial constructors).当模板参数是 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;
}

The problem is, not only VS 2005 doesn't have TR1, it won't care about the union above (which shouldn't be valid when the template parameter is not a POD), so both a and b evaluate to true.问题是,不仅 VS 2005 没有 TR1,它也不会关心上面的联合(当模板参数不是 POD 时它应该无效),所以 a 和 b 评估为真。


Thanks for the answers posted below.感谢您在下面发布的答案。 After reading carefully them (and the code) I realized that what I was trying to do was really a wrong approach.仔细阅读它们(和代码)后,我意识到我试图做的确实是一种错误的方法。 The idea was to combine SFINAE behavior with an adaptation to the template must_be_pod (which I found in the book Imperfect C++ , but it can be found in another places, too).这个想法是将 SFINAE 行为与对模板must_be_pod的适应相结合(我在Imperfect C++一书中找到了它,但它也可以在其他地方找到)。 Actually, this would require a quite particular set of rules for SFINAE, which are not what the standard defines, obviously.实际上,这将需要一套非常特殊的 SFINAE 规则,这显然不是标准定义的。 This is not really a bug in VS, after all.毕竟,这并不是 VS 中的真正错误。

The biggest problem with your approach is you don't do SFINAE here - SFINAE only applies to parameter types and return type here.你的方法最大的问题是你不在这里做 SFINAE - SFINAE 只适用于参数类型和返回类型。

However, of all the SFINAE situations in the standard, none applies to your situation.但是,在标准中的所有 SFINAE 情况中,没有一个适用于您的情况。 They are他们是

  • arrays of void, references, functions, or of invalid size void、引用、函数或无效大小的数组
  • type member that is not a type不是类型的类型成员
  • pointers to references, references to references, references to void指向引用的指针、对引用的引用、对 void 的引用
  • pointer to member of a non-class type指向非类类型成员的指针
  • invalid conversions of template value parameters模板值参数的无效转换
  • function types with arguments of type void参数类型为 void 的函数类型
  • const/volatile function type const/volatile 函数类型

That's probably why in Boost documentation, there is:这可能就是为什么在 Boost 文档中,有:

Without some (as yet unspecified) help from the compiler, ispod will never report that a class or struct is a POD;如果没有编译器的一些(尚未指定的)帮助,ispod 永远不会报告类或结构是 POD; this is always safe, if possibly sub-optimal.这总是安全的,如果可能是次优的。 Currently (May 2005) only MWCW 9 and Visual C++ 8 have the necessary compiler-_intrinsics.目前(2005 年 5 月)只有 MWCW 9 和 Visual C++ 8 具有必要的编译器-_intrinsics。

This doesn't work with VS2008 either, but I suspect you knew that too.这也不适用于 VS2008,但我怀疑您也知道这一点。 SFINAE is for deducing template arguments for template parameters; SFINAE 用于为模板参数推导模板参数; you can't really deduce the type of something that reveals the constructor-ness of a type, even though you can create a type that is incompatible with another type (ie, unions can't use non-POD).即使您可以创建与另一种类型不兼容的类型(即联合不能使用非 POD),您也无法真正推断出揭示类型构造函数的事物的类型。

In fact, VS 2008 uses compiler support for traits to implement std::tr1::type_traits .事实上,VS 2008 使用编译器对特征的支持来实现std::tr1::type_traits

I'm not sure about the way you're trying to do SFINAE here, since is_pod<T>::test(...) will match is_pod<T>::test(0) too.我不确定你在这里尝试做 SFINAE 的方式,因为is_pod<T>::test(...)也会匹配is_pod<T>::test(0) Perhaps if you use a different type instead of 'int' you'd get a better match:也许如果你使用不同的类型而不是 '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))};
};

You might also want to look at Boost.Enable_i f to do your SFINAE for you -- unless you're trying to implement your own library or for some reason.您可能还想查看Boost.Enable_if来为您执行 SFINAE —— 除非您正在尝试实现自己的库或出于某种原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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