如何在 C++ 的编译时检测结构的成员是否为位域?

How to detect whether a struct's member is a bit-field at compile time in C++?

给定一个结构 S:

struct S {
  bool a : 1;
  bool b : 1;
};

编译时如何判断S::aS::b是位域?

我试图想出一个像 IsBitField(S, a) 这样的宏,但很难将 SFINAE 与 offsetof()addressof() 一起应用(这被认为是 无效 每个位域的操作)。

首先,对于 SFINAE 解决方案,省略号重​​载技巧(使用表达式 SFINAE)仍然有效,我们只需要找到一个构造,该构造在应用于位域时格式错误,而在应用于普通位域时格式正确会员.

例如,如果成员是位域,则不能形成指向成员的指针。

所以我们可以这样写:

template <typename T>
struct is_bit_field_t {
    template <typename U>
    static constexpr bool helper(...) {
        return true;
    }
    template <typename U>
    static constexpr bool helper(decltype(&U::a) arg) {
        return false;
    }
    static constexpr bool value = helper<T>(nullptr); 
};

这将测试U的public成员a是否是位域类型。解释:

  • 如果 T::a 是位域,则表达式 decltype(&U::a) 的格式不正确,这将导致 SFINAE 出现第二个重载。

现场演示:https://godbolt.org/z/TTn8YPKW3


在 C++20 中,这可以通过概念来完成,利用不能获取位域地址的事实。

核心实现看起来像:

template <typename T>
concept A_IsBitField = !requires (T t) {
     { &t.a };
};

现场演示:https://godbolt.org/z/W3jbosY93

如果您不想定义一个独立的概念,您可以只使用 requires 表达式(使用 SFINAE 方法,您别无选择,只能创建该结构)


当然,以上仅对名为a的成员有效。如果您想将它与其他成员一起使用,则需要重写 SFINAE 特征或概念,将 a 替换为您想要的任何成员。如果您需要很多结构,您可以编写一个宏来帮助您生成这些结构。