根据唯一类型 id 比较两个 uint64_t 之间的多个位总是 returns true

Comparing multiple bits between two uint64_t's based on unique type id always returns true

我有一张地图,其中键是实体 ID (uint32_t),值是“签名”,又名 uint64_t,其中某些位集代表一种类型:std::unordered_map<uint32_t, uint64_t> m_entityComponents{};

我的目标是编写一个模板函数,它接受可变数量的类型并且 returns 无论实体中是否存在所有这些类型。我们称该函数为 bool hasAllComponents(uint32_t entity).

为此,我编写了一个方法,其中 returns 每个类型的唯一 ID:

template <class T>
uint8_t getTypeId()
{
    static uint8_t s_type = ++m_nextComponentType;
    return s_type;
}

然后,给定任意数量的类型,我通过使用折叠表达式调用 getTypeId() 来构造一个新的“签名”,将存在的每种类型的每个位设置为 1:

template<typename... Types>
uint64_t getTypesSignature()
{
    return ((1 << getTypeId<Types>()) | ... | 0);
}

鉴于这两个辅助函数,我应该能够使用我的 hasAllComponents 方法检查地图中的实体是否具有所有传入的类型,该方法使用按位 & 运算符来将地图中缓存的签名与新创建的签名进行比较:

template<typename... Types>
bool hasAllComponents(uint32_t entity)
{
    uint64_t signature = getTypesSignature<Types...>();
    return (m_entityComponents[entity] & signature);
}

然而,hasAllComponents 仍然 returns 当只有部分位匹配时为真,而不是全部。我认为问题可能出在我的 getTypesSignature 折叠逻辑没有正确设置所有位,尽管打印出结果对我来说看起来不错。我的逻辑某处存在缺陷,如能帮助追踪,我将不胜感激!

您正在生成一个 signature,其中包含设置为 1 的所有 必需的 位,但您没有正确检查实体的值是否确实具有 [=40=这些相同位的 ]all 设置为 1。您正在检查该值是否将这些相同位的 any 设置为 1。

本次比较:

return (m_entityComponents[entity] & signature);

& 运算符的结果将是 uint64_t,可隐式转换为 bool,因此 return 值将是 true如果结果 uint64_t 是 non-zero,否则它将是 false.

所以,假设计算出的 signature107 (b01101011)。这意味着值与这些位集的 any 的任何组合将导致 true,例如:

1:   b00000001 & b01101011 = b00000001, != 0? true
2:   b00000010 & b01101011 = b00000010, != 0? true
4:   b00000100 & b01101011 = b00000000, != 0? false
8:   b00001000 & b01101011 = b00001000, != 0? true
16:  b00010000 & b01101011 = b00000000, != 0? false
32:  b00100000 & b01101011 = b00100000, != 0? true
64:  b01000000 & b01101011 = b01000000, != 0? true
107: b01101011 & b01101011 = b01101011, != 0? true
128: b10000000 & b01101011 = b00000000, != 0? false
255: b11111111 & b01101011 = b01101011, != 0? true

为确保该值已设置 所有 所需位,您只需将比较更改为:

return ((m_entityComponents[entity] & signature) == signature);

仅当该值至少具有 signature 位集的 all 时(它可以有更多),结果才会是 true,例如:

1:   b00000001 & b01101011 = b00000001, == b01101011? false
2:   b00000010 & b01101011 = b00000010, == b01101011? false
4:   b00000100 & b01101011 = b00000000, == b01101011? false
8:   b00001000 & b01101011 = b00001000, == b01101011? false
16:  b00010000 & b01101011 = b00000000, == b01101011? false
32:  b00100000 & b01101011 = b00100000, == b01101011? false
64:  b01000000 & b01101011 = b01000000, == b01101011? false
107: b01101011 & b01101011 = b01101011, == b01101011? true
128: b10000000 & b01101011 = b00000000, == b01101011? false
255: b11111111 & b01101011 = b01101011, == b01101011? true