我想使用一个缓存,由boost的unordered_map
实现,从dynamic_bitset
到dynamic_bitset
。当然,问题是bitset没有默认的哈希函数。它似乎不像一个概念问题,但我不知道如何解决技术问题。我该怎么做?
答案 0 :(得分:6)
我找到了意想不到的解决方案。事实证明,boost有#define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
的选项。如果定义了这个,包括m_bits
在内的私人成员就会公开(我认为它可以处理旧的编译器或其他东西)。
所以现在我可以使用@ KennyTM的答案,改了一下:
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
return boost::hash_value(bs.m_bits);
}
}
答案 1 :(得分:3)
有to_block_range
函数将
不幸的是,dynamic_bitset
的设计是恕我直言,因为它不能让你直接访问底层缓冲区(甚至不是const
)。
答案 2 :(得分:3)
通过将bitset转换为临时向量,可以实现效率不高的唯一哈希:
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
std::vector<B, A> v;
boost::to_block_range(bs, std::back_inserter(v));
return boost::hash_value(v);
}
}
答案 3 :(得分:2)
我们无法直接计算哈希,因为dynamic_bitset
中的基础数据是私有的(m_bits
)
但我们可以很容易地在没有
的情况下过去(颠覆!)c ++访问规范系统BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
)关键是模板函数to_block_range
,它是friend
到dynamic_bitset
。因此,该功能的专业化也可以访问其私人数据(即m_bits
)。
生成的代码不能简单
namespace boost {
// specialise dynamic bitset for size_t& to return the hash of the underlying data
template <>
inline void
to_block_range(const dynamic_bitset<>& b, size_t& hash_result)
{
hash_result = boost::hash_value(bs.m_bits);
}
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs)
{
size_t hash_result;
to_block_range(bs, hash_result);
return hash_result;
}
}
答案 4 :(得分:0)
建议的解决方案在以下情况下生成相同的哈希值。
#define BOOST_DYNAMIC_BITSET_DONT_USE_FRIENDS
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
return boost::hash_value(bs.m_bits);
}
}
boost::dynamic_biset<> test(1,false);
auto hash1 = boost::hash_value(test);
test.push_back(false);
auto hash2 = boost::hash_value(test);
// keep continue...
test.push_back(false);
auto hash31 = boost::hash_value(test);
// magically all hash1 to hash31 are the same!
建议的解决方案有时候对哈希映射不合适。
我阅读了dynamic_bitset的源代码,为什么会发生这种情况,并意识到dynamic_bitset每个值存储一位与vector<bool>
相同。例如,您调用dynamic_bitset<> test(1, false)
,然后dynamic_bitset最初分配4个字节全部为零,并且它保持位的大小(在这种情况下,大小为1)。注意,如果位的大小大于32,则它再次分配4个字节并将其推回dynamic_bitsets<>::m_bits
(因此m_bits是4个字节块的向量)。
如果我调用test.push_back(x)
,它会将第二位设置为x并将位大小增加到2.如果x
为false,则m_bits[0]
根本不会更改!为了正确计算哈希值,我们需要在哈希计算中使用m_num_bits。
然后,问题是如何?
1:使用boost::hash_combine
这种方法简单直接。我没有检查这个编译与否。
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
size_t tmp = 0;
boost::hash_combine(tmp,bs.m_num_bits);
boost::hash_combine(tmp,bs.m_bits);
return tmp;
}
}
2:翻转m_num_bits%bits_per_block th bit。 根据位大小翻转一下。我相信这种方法比1快。
namespace boost {
template <typename B, typename A>
std::size_t hash_value(const boost::dynamic_bitset<B, A>& bs) {
// you may need more sophisticated bit shift approach.
auto bit = 1u << (bs.m_num_bits % bs.bits_per_block);
auto return_val = boost::hash_value(bs.m_bits);
// sorry this was wrong
//return (return_val & bit) ? return_val | bit : return_val & (~bit);
return (return_val & bit) ? return_val & (~bit) : return_val | bit;
}
}