在编译时生成位掩码

问题描述 投票:0回答:3

我想在编译时生成各种位掩码:

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++ bit-manipulation constexpr
3个回答
4
投票

使用 ,您可以使用

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
。这确保函数总是在编译时被评估。


3
投票

实现此目的的一种方法是构建所需字节的数组,然后使用

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;
};

0
投票

所以你想将你的 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);
© www.soinside.com 2019 - 2024. All rights reserved.