2013-02-13 76 views
2

有沒有一種簡單的方法做C++ 11 &升壓以下幾點:使用boost ::哈希值來定義的std ::散在C++ 11

  • 使用std::hash標準的定義,隨時可用來自<functional>
  • 使用boost::hash_value來定義std::hash,其中std::hash丟失,但boost::hash_value可用於<boost/functional/hash.hpp>

例如:

  • std::hash<std::vector<bool>>應來自標準庫,
  • std::hash<std::vector<unsigned>>應與boost::hash_value來實現。
+2

相關:http://stackoverflow.com/q/12753997/743214 – 2013-02-14 22:41:41

回答

1

我的回答可能不正確,但我會試着解釋爲什麼我認爲答案是否定的。

我不認爲std::hash<T>boost:hash<T>可以互換使用,所以我試圖隱藏對象創建(即使這不是完美的解決方案),並返回它們的結果,這是size_t。方法應該是在編譯時選擇的過程,所以功能調度就是在我腦海中,示例代碼:

template <typename T> 
size_t createHash(const T& t, false_type) 
{ 
    return boost::hash<T>()(t); 
} 

template <typename T> 
size_t createHash(const T& t, true_type) 
{ 
    return std::hash<T>()(t); 
} 

template<typename T> 
size_t createHash(const T& t) 
{ 
    return createHash<T>(t, std::is_XXX<T>::type()); 
} 


int main() 
{ 
    vector<unsigned> v; v.push_back(1); 
    auto h1 = createHash(v); 
    cout << " hash: " << h1; 
    //hash<vector<unsigned> > h2; 
} 

這段代碼的想法很簡單:如果你可以構建std::hash<T>型的類型,選擇第二個實施如果沒有 - 選擇第一個。

如果選擇第一個實現,代碼編譯沒有問題,您可以使用fe檢查它。包裝函數中的std::is_array<T>::type(),這當然不是真的,所以boost :: hash實現將被選中。但是,如果您使用的特性將返回true_t代替vector<unsigned>,如fe。 std::is_class<T>::type()然後編譯器會報告「C++ Standard does not provide ...」,這是static_assert的結果。

爲了這個工作,我們需要強制編譯器返回true_t如果一個類型真的可以構造(它不會失敗static_assert)和false_t如果不是。但是,我不認爲有這樣做的可能性。

5

浮現在腦海的第一個念頭是使用SFINAE,如果可能的話std::hash<>和以其他方式使用boost::hash_value(),像這樣:

#include <string> 
#include <functional> 
#include <type_traits> 
#include <boost/functional/hash.hpp> 

struct my_struct_0 { 
    std::string s; 
}; 

template <typename T> 
struct has_std_hash_subst { typedef void type; }; 

template <typename T, typename C = void> 
struct has_std_hash : std::false_type {}; 

template <typename T> 
struct has_std_hash< 
    T, 
    typename has_std_hash_subst<decltype(std::hash<T>()(T())) >::type 
> : std::true_type {}; 

template <typename T> 
static typename std::enable_if<has_std_hash<T>::value, size_t>::type 
make_hash(const T &v) 
{ 
    return std::hash<T>()(v); 
} 

template <typename T> 
static typename std::enable_if<(!has_std_hash<T>::value), size_t>::type 
make_hash(const T &v) 
{ 
    return boost::hash_value(v); 
} 

int main() 
{ 
    make_hash(std::string("Hello, World!")); 
    make_hash(my_struct_0({ "Hello, World!" })); 
} 

不幸的是,總有std::hash觸發static_assert失敗默認專業化。這可能與其他庫的情況下,但它與GCC 4.7.2的情況下(見bits/functional_hash.h:60):

/// Primary class template hash. 
    template<typename _Tp> 
    struct hash : public __hash_base<size_t, _Tp> 
    { 
     static_assert(sizeof(_Tp) < 0, 
        "std::hash is not specialized for this type"); 
     size_t operator()(const _Tp&) const noexcept; 
    }; 

所以上面SFINAE方法是行不通的 - static_assert中有一個表明,塞。因此,您無法確定何時可以使用std::hash。現在

,這並沒有真正回答你的問題,但可能會來方便 - 這是可能圍繞做這一招的另一種方式 - 檢查加速實施第一個也是唯一然後回落到std::hash<>。考慮使用boost::hash_value()如果可用下面的例子中(即用於std::stringmy_struct_0)和以其他方式使用std::hash<>(即用於my_struct_1):

#include <string> 
#include <functional> 
#include <type_traits> 
#include <boost/functional/hash.hpp> 

struct my_struct_0 { 
    std::string s; 
}; 

struct my_struct_1 { 
    std::string s; 
}; 

namespace boost { 
size_t hash_value(const my_struct_0 &v) { 
    return boost::hash_value(v.s); 
} 
} 

namespace std { 
template <> 
struct hash<my_struct_1> { 
    size_t operator()(const my_struct_1 &v) const { 
     return std::hash<std::string>()(v.s); 
    } 
}; 

} 

template <typename T> 
struct has_boost_hash_subst { typedef void type; }; 

template <typename T, typename C = void> 
struct has_boost_hash : std::false_type {}; 

template <typename T> 
struct has_boost_hash< 
    T, 
    typename has_boost_hash_subst<decltype(boost::hash_value(T()))>::type 
> : std::true_type {}; 

template <typename T> 
static typename std::enable_if<has_boost_hash<T>::value, size_t>::type 
make_hash(const T &v) 
{ 
    size_t ret = boost::hash_value(v); 
    std::cout << "boost::hash_value(" << typeid(T).name() 
       << ") = " << ret << '\n'; 
    return ret; 
} 

template <typename T> 
static typename std::enable_if<(!has_boost_hash<T>::value), size_t>::type 
make_hash(const T &v) 
{ 
    size_t ret = std::hash<T>()(v); 
    std::cout << "std::hash(" << typeid(T).name() 
       << ") = " << ret << '\n'; 
    return ret; 
} 

int main() 
{ 
    make_hash(std::string("Hello, World!")); 
    make_hash(my_struct_0({ "Hello, World!" })); 
    make_hash(my_struct_1({ "Hello, World!" })); 
} 

希望它能幫助。

更新:也許您可以使用@ChristianRau指出的描述here的破解方法,並使第一個SFINAE方法奏效!雖然它很骯髒:)