4

这里的原标题是 Workaround for SFINAE bug in VS2005 C++

这是对 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 行为与对模板must_be_pod的适应结合起来(我在Imperfect C++一书中找到了它,但它也可以在其他地方找到)。实际上,这需要一套非常特殊的 SFINAE 规则,这显然不是标准定义的。毕竟,这并不是 VS 中的真正错误。

4

3 回答 3

4

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

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

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

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

如果没有来自编译器的一些(尚未指定的)帮助,ispod 将永远不会报告类或结构是 POD。这总是安全的,如果可能不是最理想的。目前(2005 年 5 月)只有 MWCW 9 和 Visual C++ 8 具有必要的编译器-_intrinsics。

于 2009-02-11T00:14:54.303 回答
2

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

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

于 2009-02-11T00:06:31.953 回答
1

我不确定你在这里尝试做 SFINAE 的方式,因为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_if来为您执行 SFINAE —— 除非您尝试实现自己的库或出于某种原因。

于 2009-02-10T23:25:40.973 回答