我知道我们只能向namespace std
添加代码这是在那里定义的模板的模板特化,否则行为未定义。
我已经从 C++ 入门实现了这段代码:
//namespace std
//{
template <>
class std::hash<Sales_data>
// class hash<Sales_data>
{
public:
using result_type = std::size_t;
using argument_type = Sales_data;
result_type operator()(argument_type const& ) const;
};
typename hash<Sales_data>::result_type
hash<Sales_data>::operator()(argument_type const& arg) const
{
return hash<std::string>()(arg.isbn_) ^
hash<unsigned int>()(arg.nCopySold_) ^
hash<double>()(arg.revenue_);
}
//}
template <> class std::hash<Sales_data>
或者干脆我专攻 std::hash
在命名空间之外?原始代码使用的是未注释的行。最佳答案
Is specializing
std::hash
outside namespacestd
unsafe?
号
template<> class std::hash<Sales_data> { ... };
在全局命名空间中将导致与namespace std {
template<>
class hash<Sales_data> { ... };
}
在全局命名空间中。Shouldn't I do this or it is erroneous to do so?
这样做很好 - 但如果你像你在问题中那样做,那么旧版本的 g++(我认为版本 7 之前的版本,仍在使用中)会产生类似“warning: specialization of template in different namespace”的警告。结合
-Werror
这可能会导致完全正确的代码无法编译。我建议使用 namespace { ... }
版本。关于哈希本身的注释:
std::hash<any_type_smaller_or_of_equal_size_of_size_t>
可能是标准库中非常差的散列(更改 1 位不会翻转大约一半的其他位),返回与输入相同的输出(位模式)。这很常见,因为它非常快,并且在用作标准容器中的 key 时可以满足所有需要。每个值都会得到一个唯一的哈希值,所以从这个角度来看它是完美的。将这些组合在一起时就会出现问题。碰撞将非常容易创建 - 您希望将碰撞降至最低以在您的 unordered
中进行查找。容器快。您的 XOR
操作不会改变冲突很多的事实,所以我建议使用一个函数来组合散列。 boost
有一个常用的( boost::hash_combine
)。32 位看起来像这样
size_t
s(不确定是否在不同的 boost
版本中有所不同):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);
}
例子:namespace stolen { // from boost - use the real boost version to get proper 64 bit hashes
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);
}
}
namespace std {
template <>
class hash<Sales_data> {
public:
using result_type = std::size_t;
using argument_type = Sales_data;
result_type operator()(argument_type const& arg) const {
result_type result = hash<std::string>{}(arg.isbn_);
stolen::hash_combine(result, arg.nCopySold_);
stolen::hash_combine(result, arg.revenue_);
return result;
}
};
}
还有一个建议是添加一些版本的 hash_combine
进入标准库: hash_combine()
Again
关于c++ - 在命名空间 std 之外专门化 std::hash 是否不安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65485237/