Boost:当对包含自定义类型时,如何将"Boost::hash"与"std::pair&



我正在尝试使用以下自定义unordered_map

using pair = std::pair<char, QColor>;
using cache = std::unordered_map<pair, QPixmap, boost::hash<pair>>;
cache _cache;

我为QColor定义了如下的散列函数

template<>
struct std::hash<QColor>
{
std::size_t operator()(const QColor &color) const noexcept
{
return std::hash<QRgb>{}(color.rgb());
}
};

但无论我把它放在哪里,无论它是头文件还是源文件,我都会从boost 中得到一个详细的编译时错误

C:boost_1_77_0boostcontainer_hashextensions.hpp:305: error: C2665: 'boost::hash_value': none of the 3 overloads could convert all the argument types
C:boost_1_77_0boost/container_hash/hash.hpp(550): note: could be 'size_t boost::hash_value(const std::error_condition &)'
C:boost_1_77_0boost/container_hash/hash.hpp(543): note: or       'size_t boost::hash_value(const std::error_code &)'
C:boost_1_77_0boost/container_hash/hash.hpp(536): note: or       'size_t boost::hash_value(std::type_index)'
C:boost_1_77_0boost/container_hash/extensions.hpp(305): note: while trying to match the argument list '(const T)'

这是最后一条信息。我认为boost对pair的哈希函数并没有看到我定义的哈希函数。我需要在boost的命名空间中定义它吗?一般来说,定义模板的特定版本的规则是什么?为什么必须仅在头文件中定义模板的规则在这里不适用?

UPD:我的项目结构如下

// foo.h
#include <QtWidgets>
#include <boost/functional/hash.hpp>
#include <unordered_map>
template<>
struct std::hash<QColor>
{
std::size_t operator()(const QColor &color) const noexcept
{
return std::hash<QRgb>{}(color.rgb());
}
};
class Foo
{
private:
using Pair = std::pair<char, QColor>;
const QPixmap &getPixmapForPair(Pair c);
using CharsCache = std::unordered_map<Pair, QPixmap, boost::hash<Pair>>;
CharsCache _cache;
}
// foo.cpp
const QPixmap &Foo::getPixmapForPair(Pair c)
{
auto it = _cache.find(c);
if (it != _cache.end())
return it->second;
}

非常简单化,但传达了总体想法。

boost::hash<>可能使用了使用hash_value重载的boost::hash_combine,而它没有用于QColor的重载,这可能是一个问题,因此我建议您通过将别名从类定义中移出来为std::hash<Pair>创建一个专用化,然后直接在operator():中使用boost::hash_combine

using Pair = std::pair<char, QColor>;
namespace std {
template<>
struct hash<Pair> {
std::size_t operator()(const Pair &p) const noexcept {
std::size_t seed = 0;
boost::hash_combine(seed, p.first);
boost::hash_combine(seed, p.second.rgb());
return seed;
}
};
} // namespace std

您可能会将其设为std::size_t seed = p.first;,而不是使用0进行初始化,然后调用hash_combine

然后,您可以在创建地图时使用默认的哈希器(std::hash<Pair>(:

class Foo {
private:
const QPixmap &getPixmapForPair(const Pair &c) const;
using CharsCache = std::unordered_map<Pair, QPixmap>;
CharsCache _cache;
};

请注意,函数必须返回一个值。如果找不到匹配项,我建议您抛出一个异常:

const QPixmap& Foo::getPixmapForPair(const Pair &c) const {
auto it = _cache.find(c);
if (it != _cache.end()) return it->second;
throw std::runtime_error("getPixmapForPair"); // must return a value
}

另一个选项是为hash_value(const QColor&)提供过载,而不是为std::hash<Pair>:提供专门化

std::size_t hash_value(const QColor& c) {
return std::hash<QRgb>{}(c.rgb());
}
class Foo {
private:
using Pair = std::pair<char, QColor>;
const QPixmap& getPixmapForPair(const Pair& p) const;
using CharsCache = std::unordered_map<Pair, QPixmap, boost::hash<Pair>>;
CharsCache _cache;
};

最新更新