【问题标题】:Detecting first member of POD types for SFINAE为 SFINAE 检测 POD 类型的第一个成员
【发布时间】:2019-10-10 17:32:36
【问题描述】:

给定一些与此类似的 POD 结构:

struct StandardHeader
{
    uint32_t field1;
    uint32_t field2;
};

struct TypeA
{
    StandardHeader Header;
    uint8_t field3;
};

struct TypeB
{
    StandardHeader Header;
    uint16_t field4;
};

我想编写一个类型特征(或类似的东西,最终可以在static_assertstd::enable_if 中使用,或者禁用模板化方法),它可以检测StandardHeader 字段的存在作为第一个标准布局类型的成员——即。这样reinterpret_cast<StandardHeader*>(&instance) 是安全的。

(本质上,一个 is-a 基本类型检查,除了类型必须是 POD,如果我使用实际的 C++ 继承,这将不是真的。)

我能够编写一些使用检测习语来验证类型是标准布局并且具有正确类型的Header 成员的东西:

template<typename, typename = std::void_t<>>
struct HasStandardHeader : std::false_type {};

template<typename T>
struct HasStandardHeader<T,
        std::void_t<decltype(std::declval<T>().Header)>>
    : std::conditional_t<
        std::is_standard_layout_v<T> &&
        std::is_same_v<decltype(std::declval<T>().Header), StandardHeader>
    , std::true_type, std::false_type> {};

上述部分有效,但不能验证该字段是否是第一个。

我试图在这个表达式的行中添加一些东西来检测它,但它不起作用:

static_cast<uint8_t*>(&static_cast<T*>(0)->Header) - static_cast<uint8_t*>(0)) == 0

(其他失败的尝试涉及调用constexpr bool 方法,但遗憾的是,这些尝试在conditional_t 中似乎无效。或者至少在使用&amp; 或其他方法时无效。)

理想情况下,我更喜欢只检测到具有正确类型的字段的东西,甚至不需要将其命名为Header。那可能吗?有没有更好的方法来重写上面的内容?

如前所述,最终目标是制作此方法:

template<typename T>
bool Process(T& data, size_t len);

如果 T 不是具有正确第一个成员的 POD 类型,则消失或 static_assert


编辑:看起来我可能有点过于复杂了。添加此表达式使其按预期工作:

offsetof(T, Header) == 0

但是现在:

  • 有没有更好的方法来写这整件事?
  • 是否可以这样写,这样我们就不需要将字段称为Header

【问题讨论】:

    标签: c++ metaprogramming c++17 sfinae typetraits


    【解决方案1】:

    只检查成员的偏移量。

    template<typename, typename = std::void_t<>>
    struct HasStandardHeader : std::false_type {};
    
    template<typename T>
    struct HasStandardHeader<T,
            std::void_t<decltype(std::declval<T>().Header)>>
        : std::conditional_t<
            std::is_standard_layout<T>::value &&
            std::is_same<decltype(std::declval<T>().Header), StandardHeader>::value &&
            offsetof(T, Header) == 0
        , std::true_type, std::false_type> {};
    

    godbolt 上进行了一些测试。

    【讨论】:

    • 呵呵,看来我们俩同时想到了。 :)
    • 这不是我整个问题的答案。这是对原始问题的回答,在发布之前我已经用类似的代码和后续问题进行了更新。
    猜你喜欢
    • 1970-01-01
    • 2011-03-23
    • 2013-09-05
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多