std::类似映射的类型,键上没有compare/hash
std::map-like type without compare / hash on key
我刚刚遇到一个小问题,想知道在众多解决方案中哪一个是最好/合适的。
我有一个std::map
,它为每个键和值都有一个自定义类(所以交换它们不会解决任何问题)。
struct FooStruct
{
bool testOne;
bool testTwo;
};
struct BarStruct
{
// some data
};
const std::map<FooStruct, BarStruct>
{
{ { true, false }, BarStruct(someValues) },
{ { false, true }, BarStruct(someOtherValues) }
};
所以现在,FooStruct
不能以任何合理的方式"比较",BarStruct
也不能。使用unordered_map
也没有帮助,因为这需要一个哈希函数,我当然可以用很多方法实现它,但我怀疑这是否是获得真正未排序映射的最简单方法。
我也不关心性能,因为地图中只有4个元素。不过下次可能会有几千。
针对评论:这是一个抽象的例子。问题是,如果有几个测试,就可以很容易地比较结构中布尔测试结果的集合,但由于排列的数量随着n的增长而快速增长,我正在寻找一个可扩展的解决方案。
也许总体上有std::map
类型的替代方案,例如std::pair
的std::vector
,但也有其他缺点。
如果你的结构FooStruct
有很多测试结果,那么你有不同的结构,比如这样,测试的数量也不同,而你没有一个可扩展的解决方案。
使用bitset
(ref)编写一个可扩展的版本。例如,您可以使用bitset::to_ulong
(ref)进行比较(假设您的测试结果少于64个)。
struct FooStruct
{
std::bitset<5> result; // can hold 5 results
friend bool operator<(const FooStruct& a, const FooStruct& b) {
return a.result.to_ulong() < b.result.to_ulong();
}
};
否则,您必须手动聚合。例如:
struct FooStruct
{
bool testOne;
bool testTwo;
bool testThree;
unsigned long key() const {
return testOne + (testTwo << 1) + (testThree << 2);
}
friend bool operator<(const FooStruct& a, const FooStruct& b) {
return a.key() < b.key();
}
};
比较是否"合理"并不重要,重要的是它实现了严格的弱排序。这很容易实现。
#include <tuple>
bool comp(const FooStruct& lhs, const FooStruct& rhs)
{
return std::tie(lhs.testOne, lhs.testTwo) <
std::tie(rhs.testOne, rhs.testTwo);
}
至于unordered_map
,它是一个哈希表,因此您需要提供一个哈希函数和一个相等性比较。没有办法绕过这一点。
另一个"可扩展"解决方案:
using FooStruct = std::vector<bool>;
std::map<FooStruct, BarStruct> foobarite
{
{ { true, false }, {} },
{ { false, true }, {} },
};
而且,如果你想在FooStruct中保留命名属性,还有另一个:
#include <unordered_map>
#include <functional>
#include <algorithm>
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
template <typename Struct>
struct hash {
inline std::size_t operator()(const Struct& obj ) const
{
const unsigned char* p = reinterpret_cast<const unsigned char*>( &obj );
std::size_t seed = std::hash<unsigned char>{}(p[0]);
for (unsigned int i = 1; i < sizeof(obj); ++i) {
hash_combine(seed, p[i]);
}
return seed;
}
};
template <typename Struct>
struct equal {
bool operator()(const Struct& a, const Struct& b) const
{
const unsigned char* pa = reinterpret_cast<const unsigned char*>( &a );
const unsigned char* pb = reinterpret_cast<const unsigned char*>( &b );
return std::equal(pa, pa+sizeof(Struct), pb);
}
};
struct FooStruct {
bool testOne;
bool testTwo;
};
std::unordered_map<FooStruct, BarStruct, hash<FooStruct>, equal<FooStruct>> foobarite
{
{ { true, false }, {} },
{ { false, true }, {} }
};
相关文章:
- 什么是"#include <boost/functional/hash.hpp> "?
- 对自定义类使用 std::hash<uint64_t>
- 禁用/覆盖 -werror=sign-compare
- std::set<Key,Compare,Allocator>::find() 函数使用"<"运算符而不是"=="运算符背后的直觉是什么?
- 为什么我需要包含<compare>标头才能编译 <=>?
- std::hash<std::string> 可以为不同的字符串返回相同的值吗?
- C++std::hash实现总是确定性的吗
- std::hash for std::chrono::duration
- s.compare 成员函数在下面的C++代码中的行为如何?
- C++有"not equal compare and exchange"或"fetch add on not equal"吗?
- 为什么 .compare 返回 1?
- Hash for a std::pair, for use in an unordered_map
- 为什么在这种特殊情况下不需要将 std::hash() 的专用化注入到 std 命名空间中?
- std::string::compare(const char*) 会抛出异常吗?
- 为什么当我在MD5 Hash中转换相同的C 字符串时,每次都会获得不同的输出
- 在使用 JNI 将 c++ unordered_map转换为 java hashMap之前将其转换为 java hash
- "The C++ Library doesen't provide a hash for this type." - 在 std::unordered_map 中使用自己的类
- Qt/C++ hash of hashes
- 关于 C++ 中的'compare'函数
- std::类似映射的类型,键上没有compare/hash