我正在尝试为矢量定义一个哈希。我有一个简单类型的主要模板,以及具有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;
}
};
答案 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;
}