我遇到了一个小问题,并想知道许多解决方案中哪一个是最好的/适当的。
我有一个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::vector
的{{1}},但也有其他缺点。
答案 0 :(得分:2)
如果比较是“明智的”并不重要,重要的是它实现了严格的弱排序。这很容易实现。
#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
,它是一个哈希表,因此您需要提供哈希函数和相等比较。没有办法解决这个问题。
答案 1 :(得分:2)
如果您的结构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();
}
};
答案 2 :(得分:0)
另一个&#34;可扩展&#34;解决方案:
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 }, {} }
};