![]() |
Home | Libraries | People | FAQ | More |
boost::hash 盡可能按照可移植的要求寫成,但是,不幸的是,若干早期版本的編譯器不支持參數以來查找(argument dependent lookup (ADL))——用於定制化的機制。在這些編譯器上,定制化重載 hash_value 需要聲明在 boost 名字空間中。
在一個嚴格符合標準的編譯器上,當 boost::hash 被實例化時,定義在 boost 名字空間中的重載不會被找到,所以在這些編譯器上重載和類應該聲明在同一個名字空間中。
假設我們有一個簡單的定制類型:
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
friend std::size_t hash_value(custom_type x)
{
boost::hash<int> hasher;
return hasher(x.value);
}
};
}
在一個符合標準的編譯器上,當這個類型調用 hash_value 時,它會查找這個類型內部的名字空間並找到 hash_value,但是在不支持 ADL 的編譯器上,找不到,hash_value。讓事情變得更糟糕的是,有些支持 ADL 的編譯器不會發現定義在類內部的友元類。
所以,首先要將這個成員函數移出這個類:
namespace foo
{
template <class T>
class custom_type
{
T value;
public:
custom_type(T x) : value(x) {}
std::size_t hash(custom_type x)
{
boost::hash<T> hasher;
return hasher(value);
}
};
template <class T>
inline std::size_t hash_value(custom_type<T> x)
{
return x.hash();
}
}
不幸的是,因為有些編譯器不支持模板友元,我不能將 hash_value 聲明為友元,所以我聲明了一個成員函數來計算散列,再從 hash_value 中調用它。
對於不支持 ADL 的編譯器,hash_value 要定義在 boost 名字空間中:
#ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP namespace boost #else namespace foo #endif { template <class T> std::size_t hash_value(foo::custom_type<T> x) { return x.hash(); } }
這個例子的完整代碼在 /libs/functional/hash/examples/portable.cpp。
在 Visual C++ 版本 6.5 和 7.0 中,hash_value 沒有為內建數組重載。boost::hash, boost::hash_combine 和 boost::hash_range 都使用一個 workaround 來支持內建數組,所以在大多數情況下,這不再是個問題。
在 Visual C++ 版本 6.5 和 7.0 中,函數指針沒有被正確地支持。
在 Solaris 上使用 GCC 時,boost::hash_value(long double) 將 long doubles 當做 doubles 處理——所以散列函數不會考慮整個值域空間。