我想在编译时生成各种位掩码:
0x11111111
或0x1111111111111111
0xF0F0F0F0
或0xF0F0F0F0F0F0F0F0
大小将取决于类型,32 位或 64 位。
例如:
template <typename T> genMask(unsigned char templt) {
....
};
genMask<uint32_t>(0xF0);
genMask<uint64_t>(0xF0);
第一次调用应该生成
0xF0F0F0F0
,而第二次调用genMask
应该生成0xF0F0F0F0F0F0F0F0
目前我有这些硬编码。
这里的任何想法将不胜感激。
使用 c++20,您可以使用
std::bit_cast
实现此目的:
template <std::unsigned_integral T>
constexpr T genMask(unsigned char templt) {
std::array<unsigned char, sizeof(T)> mask;
std::fill(std::begin(mask), std::end(mask), templt);
return std::bit_cast<T>(mask);
}
如果你只想用编译时参数调用这个函数,你应该使用
consteval
而不是 constexpr
。这确保函数总是在编译时被评估。
实现此目的的一种方法是构建所需字节的数组,然后使用
std::bit_cast
将这些位转换为目标类型。那会给你
template <typename T>
constexpr T genMask(unsigned char val)
{
unsigned char bytes[sizeof(T)];
for (auto& e : bytes)
e = val;
return std::bit_cast<T>(bytes);
};
int main()
{
std::cout << std::hex << genMask<uint32_t>(0xF0) << " " << genMask<uint64_t>(0xF0);
}
输出
f0f0f0f0 f0f0f0f0f0f0f0f0
如果你不能使用
std::bit_cast
那么你可以自己做位操作
template <typename T>
constexpr T genMask(unsigned char val)
{
T ret{val};
for (std::size_t i = 0; i < sizeof(T) - 1; ++i)
{
ret <<= 8;
ret |= val;
}
return ret;
};
所以你想将你的 1 字节模式乘以
0x01010101...
(重复你的类型的适当长度)。
你会注意到,如果你的模式是
0xFF
,那么你最终会得到0xFFFFFFFF...
,或者该类型的最大值,所以除以0xFF
将得到你的模式0x01
。
话虽如此:
template <typename T> constexpr T genMask(unsigned char templt) {
constexpr T multiplier{std::numeric_limits<std::make_unsigned_t<T>>::max() / 0xFFu};
return multiplier * T{templt};
}
static_assert(genMask<std::uint32_t>(0xF0) == 0xF0F0F0F0);
static_assert(genMask<std::uint64_t>(0xA2) == 0xA2A2A2A2A2A2A2A2);