在编译时生成位掩码

4

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

0x111111110x1111111111111111

0xF0F0F0F00xF0F0F0F0F0F0F0F0

大小将取决于类型,可以是32位或64位。

例如:

template <typename T> genMask(unsigned char templt) {
  ....
};

genMask<uint32_t>(0xF0);
genMask<uint64_t>(0xF0);

第一次调用应该生成0xF0F0F0F0,而对genMask的第二次调用应该生成0xF0F0F0F0F0F0F0F0

目前我已经将它们硬编码。

在这里任何想法都会受到极大的赞赏。

编辑:以下是一种老派的实现方式:

#define MASK(b) ((T(-1) / 0xFF) * (b))

其中T是类型。


1
我认为这是一个不错的起点:https://dev59.com/v3jfs4cB2Jgan1znQp6E - orhtej2
1
你所展示的值只是 std::numeric_limits<T>::max() / 0xFF * 0x11std::numeric_limits<T>::max() / 0xFF * 0xF0 - Eric Postpischil
4个回答

6

使用 ,您可以通过 std::bit_cast 实现此操作:

template <std::unsigned_integral T>
constexpr T genMask(unsigned char templt) {
  std::array<unsigned char, sizeof(T)> mask;
  mask.fill(templt);
  return std::bit_cast<T>(mask);
}

如果你想确保这个函数只能返回编译时常量,你可以使用consteval限定符,但是通过在constexpr变量的初始化器中调用上面的函数,或者作为非类型模板参数来实现相同的效果已经足够了。

为了使其编译通过,我需要初始化掩码: std::array<unsigned char, sizeof(T)> mask = {0}; - Jacko
1
请注意,std::array 有自己的 fill() 方法,自 C++20 起是 constexpr 的:mask.fill(templt); - Remy Lebeau
1
@Jacko 对我来说很好用:https://godbolt.org/z/K4qe1qsqW - Patrick Roberts

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

所以,目前我有 #define FOO 0xf0f0f0f0 我该如何使用上面的genMask重写它? - Jacko
3
内联constexpr自动FOO = genMask<type_desired>(0xF0); - NathanOliver

3

所以你想要将你的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);

0

您可以使用这个:

template <typename T>
T genMask(unsigned char templt) {
  return (T)(0x0101010101010101ULL * templt);
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接