【发布时间】:2021-09-04 08:42:24
【问题描述】:
我正在玩一个基于Type-safe Bitmasks in C++ 的通用位掩码类,这是一个最简单的例子来突出我的问题 (Compiler Explorer link here):
#include <type_traits>
#include <cstdint>
#include <iostream>
template<class EnumType,
// Ensure that Bitmask can only be used with enums
typename = std::enable_if_t<std::is_enum_v<EnumType>>>
class Bitmask
{
// Type to store bitmask. Should possibly be bigger
using underlying_type = std::underlying_type_t<EnumType>;
public:
constexpr Bitmask(EnumType option) : m_mask(bitmaskValue(option))
{std::cout << "Bitmask " << (int)m_mask << "\n";}
private:
// m_mask holds the underlying value, e.g. 2 to the power of enum value underlying_type
m_mask{0};
static constexpr underlying_type bitmaskValue(EnumType o)
{ return 1 << static_cast<underlying_type>(o); }
explicit constexpr Bitmask(underlying_type o) : m_mask(o) {}
};
enum class Option : uint8_t
{
a, b, c, d, e, f, g, h, i
};
enum class Option2 : int
{
a, b, c, d, e, f, g, h, i
};
int main()
{
Bitmask<Option> b1{Option::a};
Bitmask<Option> b2{Option::h};
Bitmask<Option> b3{Option::i};
Bitmask<Option2> b4{Option2::i};
}
// Output
Bitmask 1
Bitmask 128
Bitmask 0
Bitmask 256
简而言之,只要底层类型的位数多于使用的最高枚举值,Bitmask 类型就可以正常工作。否则,bitmaskValue 函数将溢出,不会给出所需的结果,如输出所示,其中 b3 的值为 0,而不是 256。
我当然明白 uint8_t 不能存储超过 8 个不同的位,所以我想要的是某种方法使它成为编译器错误,无论是在声明 Bitmask<Option> 时,还是在使用太高的值设置位掩码时。
我尝试将 bitmaskValue 方法更改为:
static constexpr underlying_type bitmaskValue(EnumType o) {
if constexpr (std::numeric_limits<underlying_type>::digits >= static_cast<underlying_type>(o)) {
return 1 << static_cast<underlying_type>(o);
} else {
// some error
}
}
...但是我得到了错误,'o' 不是一个常量表达式。
任何人都可以在这里帮助我正确的方向吗?作为记录,我们的项目目前使用的是 gcc 9.2/c++17,不过我希望我们能尽快升级到 gcc 11.1/c++20。
谢谢。
【问题讨论】:
-
只有当
Bitmask对象被(或者更确切地说必须是)常量初始化时,你才会得到一个编译时错误。有用吗? -
我对@987654329@ 使用了不同的方法(更像是C 位掩码)。不知道我的implementation能不能帮到你(找
make_bitmask)。你可以检查一个测试here -
您能否尝试在
EnumType上对bitmaskValue函数进行模板化,而不是将其作为参数传入?template <EnumType o>应该可以解决问题。