C++:将自定义哈希键值从 unordered_map 输出到 std::cout 时出错
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
,代码可以正确编译和运行。我知道输出不会是双精度的向量。我确实环顾了 SO 一段时间,但我找不到有关如何从具有自定义键类型的无序映射中std::cout
哈希值的明确答案。任何反馈将不胜感激。
提前谢谢你!
编辑:
谢谢大家的投入。这是我第一次遇到非基元类型作为散列键,所以我对键/值对的存储方式有错误的想法(我假设散列值是键,而实际上它是实际的自定义类型(。
unordered_map<K,V>
的value_type
是pair<const K, V>
。这就是您使用范围进行迭代时得到的结果。vector
秒没有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
。
- 在while循环中输入带有std::cin的字符串后,控制台会输出大量胡言乱语
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- std::cout输出int时出现编译错误
- 使用 std::string_view 的子字符串控制台输出
- C++:将 std::set_union() 输出存储在 std::multiset 中
- 使输出流式处理运算符适用于 boost::variant<std::vector<int>、int、double 的正确方法是什么>
- 为什么'std::cout << !+2 '输出 0?
- 对于输出,std::copy是否比std::cout快
- 自定义堆栈上 std::string 数据的输出
- C++11 中 std::to_string 的奇怪输出
- 如何使用 rapidjson 读取 json 文件并输出到 std::string?
- std::cout 如果从自定义分配器 (Visual Studio 2019) 调用,则不会输出
- 为什么将字符串输出到未命名的 std::ofstream 反而给了我一个十六进制数?
- 为什么 std::accumulate 生成705032704作为输出,而不是向量中元素的总和?
- std::out_of_range异常奇怪的输出
- C 输出:STD :: COUT和文件输出没有相同的内容
- 输出“std::multiset”的唯一元素及其频率,使用C++中的std::算法(无循环)
- ofstream 输出 std::map<UnicodeString, UnicodeString> 产生地址而不是字符串
- 位移位数字给出错误的输出' std::cout '
- 混合的奇怪输出 std::cout