我有一个std::unordered_map
容器,其中Key
可以是两种数据类型:
但是值是两个键类型都相同的对象类型。
我尝试过的一件事是将键设置为std::variant
,以便它可以容纳两种类型。根据一些条件检查,将密钥设置为以下类型之一:
void A::a() {
std::varaint<type1, type2> Id; //key
if (condition) {
Id = 64 bit unsigned value;
}
else {
Id = tuple<.....>;
}
}
unorderedmap[Id] = obj1;
// ^-- gives compile-time error
// (expecting Id specialized to either of the variant types)
此外,类似于此函数,还有多个函数在unordered_map
上执行find()。
unorderedmap.find(Id);
// ^-- Here also, compiler is throwing similar error
是否可以解决std :: variant,还是应该使用其他方法?
答案 0 :(得分:3)
这似乎很好:
#include <iostream>
#include <unordered_map>
#include <string>
#include <variant>
typedef std::variant<int, std::string> mytype;
std::unordered_map<mytype, int> m;
int main()
{
m[5] = 20;
std::cout << m[5];
m["hey"] = 10;
std::cout << m["hey"];
mytype tmp = "hey";
std::cout << m[tmp];
}
因此,答案基本上是:确保如果尝试使用变体对地图建立索引,则地图的索引具有相同的变体类型。如果您使用get
或this,则当map
是您要使用的变体的超集时,甚至可以使其工作-紧密模拟动态语言。
如果您想支持std::tuple
,则有两种选择。
只需使用std::map
而不是std::unordered_map
。您不太可能看到logN
,而且根据经验std::map
实际上会更快(您也不会因为每次进行{{{ 1}}必须增长)。
继续使用std::unordered_map
,但实施哈希处理。一个示例为here,其代码如下:
std::unordered_map
您可以将所有内容放在标题的#include <iostream>
#include <string>
#include <variant>
#include <unordered_map>
// #include "custom_tuple.h"
// CUSTOM_TUPLE.h
#include <tuple>
namespace std{
namespace
{
// Code from boost
// Reciprocal of the golden ratio helps spread entropy
// and handles duplicates.
// See Mike Seymour in magic-numbers-in-boosthash-combine:
// https://stackoverflow.com/questions/4948780
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
seed ^= hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
}
// Recursive template code derived from Matthieu M.
template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
struct HashValueImpl
{
static void apply(size_t& seed, Tuple const& tuple)
{
HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
hash_combine(seed, get<Index>(tuple));
}
};
template <class Tuple>
struct HashValueImpl<Tuple,0>
{
static void apply(size_t& seed, Tuple const& tuple)
{
hash_combine(seed, get<0>(tuple));
}
};
}
template <typename ... TT>
struct hash<std::tuple<TT...>>
{
size_t
operator()(std::tuple<TT...> const& tt) const
{
size_t seed = 0;
HashValueImpl<std::tuple<TT...> >::apply(seed, tt);
return seed;
}
};
}
// END CUSTOM_TUPLE.h
typedef std::variant<std::string, std::tuple<int, bool>> mytype;
std::unordered_map<mytype, int> m;
int main()
{
m[std::tuple{5, false}] = 20;
std::cout << m[std::tuple{5, false}];
m["hey"] = 10;
std::cout << m["hey"];
mytype tmp = "hey";
std::cout << m[tmp];
}
部分内部,然后仅在所需的位置包含该标题(我省略了包括警卫的内容,因此请照常添加)。如果该标准能够赶上并实现元组哈希,只需删除头文件即可。