【问题标题】:Using SFINAE to detect POD-ness of a type in C++使用 SFINAE 检测 C++ 中类型的 POD-ness
【发布时间】:2021-01-03 23:36:20
【问题描述】:

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

这是对 SFINAE 的尝试性使用,以等效于 TR1 中存在的 is_pod 模板类(在 VS2005 中还没有 TR1)。当模板参数是 POD 类型(包括原始类型和由它们构成的结构)时,它的 value 成员应该有它的成员,而当它不是时(比如非平凡的构造函数),它应该有它的 value 成员。

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 都计算为真的。


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

【问题讨论】:

    标签: c++ visual-studio-2005 sfinae


    【解决方案1】:

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

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

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 我尝试使用另一种类型,而不是您通过 char * 建议的空结构,但无济于事。我只是尝试使用您的示例,但它给出了相同的结果(对于 POD 和非 POD 都是如此)。
        • 关于 enable_if,我正在考虑采用类似的方法,但这将迫使我手动选择是/不是 POD 的类型,而我的偏好是将这个负担交给编译器跨度>
        • 我也知道 Boost 有一个类似于 is_pod 的模板(事实上,TR1 的大部分内容都是在 Boost 中得到启发的,这可能是另一个例子),但我宁愿不向一个功能添加依赖项无论如何,将来应该成为标准的一部分。
        猜你喜欢
        • 2012-08-27
        • 2012-08-27
        • 2019-10-10
        • 2011-06-08
        • 1970-01-01
        • 2012-05-29
        • 2013-02-20
        相关资源
        最近更新 更多