c++-如何在C++编译时检测结构的成员是否为位域?
给定一个结构 S:
struct S {
bool a : 1;
bool b : 1;
};
如何确定S::a和S::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);
};
这将考验公众成员是否a的U是位字段类型。解释:
- 如果
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为您想要的任何成员。如果您需要大量这些结构,您可以编写一个宏来帮助您生成这些结构。