Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Portability(可移植性)

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

Other Issues(其它問題)

在 Visual C++ 版本 6.5 和 7.0 中,hash_value 沒有為內建數組重載。boost::hash, boost::hash_combineboost::hash_range 都使用一個 workaround 來支持內建數組,所以在大多數情況下,這不再是個問題。

在 Visual C++ 版本 6.5 和 7.0 中,函數指針沒有被正確地支持。

在 Solaris 上使用 GCC 時,boost::hash_value(long double)long doubles 當做 doubles 處理——所以散列函數不會考慮整個值域空間。


PrevUpHomeNext