![](/img/trans.png)
[英]Unordered_map of unordered_map vs custom hash function for pair key C++?
[英]C++: Error outputting a custom hash key value from unordered_map to std::cout
我正在尝试使用自定义类型作为键来构建std::unordered_map
。 自定义类型是简单的std::vector<double>
。 这个想法是,它将充当网格上2D点的便捷容器。 除了输出散列键之外,其他所有东西都正常工作。 我整理了一个示例来说明这个想法:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <boost/functional/hash.hpp>
#include <chrono>
namespace std
{
template<typename Container>
struct hash {
std::size_t operator()(Container const& v) const
{
return boost::hash_range(v.begin(), v.end());
}
};
}
int main()
{
std::unordered_map<std::vector<double>, double> test;
unsigned long t = (unsigned long) std::chrono::system_clock::now().time_since_epoch().count();
std::srand(t);
for (uint i = 0; i < 100 ; ++i)
{
double d1 = i/200.0;
double d2 = i/200.0;
std::vector<double> v({d1, d2});
test[v] = d1;
}
std::cout << "Size:" << test.size() << std::endl;
for (const auto& it : test )
{
std::cout << it.first << ":" << it.second << std::endl;
}
return 0;
}
哈希专门化模板由另一个SO线程提供。 问题是当我尝试编译以上代码时,g ++会吐出以下错误:
cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
std::cout << it.first << ":" << it.second << std::endl;
^
很明显,它it.first
。 如果我删除it.first
,代码将编译并正确运行。 我知道输出不会是双精度的向量。 我确实四处逛逛,但是我找不到关于如何从具有自定义键类型的无序映射中std::cout
哈希值的确切答案。 任何反馈将不胜感激。
先感谢您!
编辑:
谢谢大家的投入。 这是我第一次遇到非原始类型作为散列键的情况,因此我对键/值对的存储方式有错误的认识(我假设散列值是键,而实际上是实际的自定义类型) 。
unordered_map<K,V>
的value_type
是pair<const K, V>
。 那就是当您对范围进行迭代时所得到的。 vector
s没有operator<<
重载,从而导致您看到的错误。
namespace std
{
template<typename Container>
struct hash {
std::size_t operator()(Container const& v) const
{
return boost::hash_range(v.begin(), v.end());
}
};
}
这不是std::hash
的专业化。 它是对主模板的重新定义,在您的情况下,该模板仅由纯偶然性编译。 (该实现将必须保留未定义的主要std::hash
模板,并且必须在std
名称空间而不是内联名称空间中实际声明hash
。例如,您的代码在libc ++上完全崩溃 。)
一个专业化看起来像
namespace std
{
// full specialization
template<>
struct hash<Foo> {
// ^^^^^
std::size_t operator()(Foo const& v) const
{
// ...
}
};
// partial specialization
template<typename T>
struct hash<Bar<T>>{
// ^^^^^^^^
std::size_t operator()(Bar<T> const& v) const
{
// ...
}
};
}
注意hash
的显式模板参数列表。 这表明这是专业化。
无论如何,将std::hash
专门用于std::vector<double>
是非法的,因为它不依赖于用户定义的类型。 编写自己的哈希器很容易:
struct container_hasher {
template<typename Container>
std::size_t operator()(Container const& v) const
{
using std::begin;
using std::end;
return boost::hash_range(begin(v), end(v));
}
};
请注意,我对operator()
而不是类型本身进行了模板化-这使编写哈希器类型更加容易。 using
后跟不合格的调用使ADL可以begin
和end
。
然后test
的定义变成
std::unordered_map<std::vector<double>, double, container_hasher> test;
据我所知,没有标准接口可用于从std::unordered_map
公开哈希值(与哈希函数相对)。
如您所见,取消引用std::unordered_map<Key,V>::iterator
产生可转换为std::unordered_map<Key,V>::value_type
,而后者又是std::pair<const Key,V>
代表(键,值)对,而不是(散列的键,值)对。
相应地, it.first
首先给您一个std::vector<double>
而不是std::size_t
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.