为向量定义哈希:模板参数在部分特化中不可推导

时间:2016-01-07 23:15:51

标签: c++ templates c++11 c++14

我正在尝试为矢量定义一个哈希。我有一个简单类型的主要模板,以及具有operator()的类的专门化。 但是,我收到错误template parameters not deducible in partial specialization。有人可以指出为什么吗?

 template <typename T> struct hash<vector<T>>
  {
    size_t operator()(const vector<T> &x) const
    {
        size_t res = 0;

        for(const auto &v:x) {
            boost::hash_combine(res,v);
        }

        return res;
    }
  };

  template <typename T> struct hash<vector<enable_if_t<true_t<decltype(sizeof(declval<T>()()))>::value, T>>>
  {
    size_t operator()(const vector<T> &x) const
    {
        size_t res = 0;

        for(const auto &v:x) {
            boost::hash_combine(res,v());
        }

        return res;
    }
  };

3 个答案:

答案 0 :(得分:6)

我不喜欢这里的部分特化,特别是因为它会导致代码重复。

template <typename T> 
struct hash<vector<T>>
{
    template<class T>
    static auto call_if_possible(const T& t, int) -> decltype(t()) { return t(); }
    template<class T>
    static auto call_if_possible(const T& t, ...) -> decltype(t) { return t; }

    size_t operator()(const vector<T> &x) const
    {
        size_t res = 0;
        for(const auto &v:x) {
            boost::hash_combine(res,call_if_possible(v, 0));
        }
        return res;
    }
};

(如果此hash实际上是std::hash,那么答案是“不要这样做。”除非专业化取决于用户定义的类型,否则您可能不会专门化标准库模板。 )

答案 1 :(得分:1)

T内的第二个模板专精enable_if位于non-deduced context中,因此编译器无法推断出它。它实际上与:

相同
template<typename T>
struct Identity
{
    using type = T;
}

template<typename T>
void f(typename Identity<T>::type x){} // T is non-deducible

此外,你有一个&#34; double&#34;不可导入的上下文,因为T内包含decltype的表达式是不可导出的。

答案 2 :(得分:0)

它的价值,这是我的第一次尝试 - 处理hash_value的ADL查找以及boost命名空间中的一个:

#include <iostream>

#include <boost/functional/hash.hpp>
#include <vector>

template<class T>
struct hash_value_defined
{
    template<class U> static auto boost_hash_value_test(U*p) -> decltype(boost::hash_value(*p),
                                                             void(),
                                                             std::true_type());

    template<class U> static auto adl_hash_value_test(U*p) -> decltype(hash_value(*p),
                                                             void(),
                                                             std::true_type());

    template<class U> static std::false_type boost_hash_value_test(...);
    template<class U> static std::false_type adl_hash_value_test(...);

    static constexpr bool boost_value = decltype(boost_hash_value_test<T>(nullptr))::value;
    static constexpr bool adl_value = decltype(adl_hash_value_test<T>(nullptr))::value;
    static constexpr bool value = boost_value or adl_value;
};

template<class T, class A, std::enable_if_t<hash_value_defined<T>::value> * = nullptr >
size_t hash_value(const std::vector<T, A>& v) {
    size_t seed = 0;
    for(const auto& e : v) {
        boost::hash_combine(seed, e);
    }
    return seed;
}



int main()
{
    using namespace std;

    vector<int> x { 1, 2, 3, 4, 5 };
    auto h = hash_value(x);
    cout << h << endl;
    return 0;
}