使用 SFINAE 检测 C++ 中类型的 POD 性;

发布于 2024-07-13 15:19:47 字数 1202 浏览 8 评论 0原文

这里原来的标题是 VS2005 C++ 中 SFINAE 错误的解决方法

这是暂时使用 SFINAE 来为 TR1 中存在的 is_pod 模板类创建等效项(在 VS2005 中还没有 TR1)。 当模板参数是 POD 类型(包括基本类型和由它们组成的结构)时,它的 value 成员应该为 true;当模板参数不是 POD 类型时(如非平凡的构造函数),它的 value 成员应该为 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 行为与对模板 must_be_pod 的改编结合起来(我在《Imperfect C++》一书中找到了它,但也可以在其他地方找到它)。 实际上,这需要 SFINAE 制定一套非常特殊的规则,显然这不是标准定义的。 毕竟,这并不是 VS 中的一个真正的错误。

The original title here was
Workaround for SFINAE bug in VS2005 C++

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). 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).

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.


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). Actually, this would require a quite particular set of rules for SFINAE, which are not what the standard defines, obviously. This is not really a bug in VS, after all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

初雪 2024-07-20 15:19:47

您的方法的最大问题是您在这里不执行 SFINAE - SFINAE 仅适用于此处的参数类型和返回类型。

然而,在标准中的所有 SFINAE 情况中,没有一个适用于您的情况。 它们是

  • void、引用、函数或非
  • 类型成员的无效大小的数组 指向引用的类型
  • 指针、对引用的引用、对指向
  • 非类类型成员的 void 指针的
  • 引用模板值参数函数
  • 类型 的参数
  • 的无效转换void const/volatile 函数类型

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

没有一些(尚未指定)帮助
从编译器来看,ispod 永远不会
报告一个类或结构是
荚; 如果可能的话,这总是安全的
次优。 目前(2005 年 5 月)仅
MWCW 9 和 Visual C++ 8 具有
必要的编译器-_intrinsics。

The biggest problem with your approach is you don't do SFINAE here - SFINAE only applies to parameter types and return type here.

However, of all the SFINAE situations in the standard, none applies to your situation. They are

  • arrays of void, references, functions, or of invalid size
  • type member that is not a type
  • pointers to references, references to references, references to void
  • pointer to member of a non-class type
  • invalid conversions of template value parameters
  • function types with arguments of type void
  • const/volatile function type

That's probably why in Boost documentation, there is:

Without some (as yet unspecified) help
from the compiler, ispod will never
report that a class or struct is a
POD; this is always safe, if possibly
sub-optimal. Currently (May 2005) only
MWCW 9 and Visual C++ 8 have the
necessary compiler-_intrinsics.

山川志 2024-07-20 15:19:47

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

事实上,VS 2008 使用编译器对特征的支持来实现 std::tr1::type_traits

This doesn't work with VS2008 either, but I suspect you knew that too. SFINAE is for deducing template arguments for template parameters; 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 (i.e., unions can't use non-POD).

In fact, VS 2008 uses compiler support for traits to implement std::tr1::type_traits.

如梦 2024-07-20 15:19:47

我不确定你在这里尝试执行 SFINAE 的方式,因为 is_pod::test(...) 将匹配 is_pod::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_if 为您执行 SFINAE - 除非您尝试实现自己的库或出于某种原因。

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. Perhaps if you use a different type instead of 'int' you'd get a better match:

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_if to do your SFINAE for you -- unless you're trying to implement your own library or for some reason.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文