如何在 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::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);
};
这将测试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
替换为您想要的任何成员。如果您需要很多结构,您可以编写一个宏来帮助您生成这些结构。
给定一个结构 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);
};
这将测试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
替换为您想要的任何成员。如果您需要很多结构,您可以编写一个宏来帮助您生成这些结构。