我正在尝试专门化哈希以包括所有算术类型的 std::vector,但它会抛出一些错误
./includes/helpers.hpp:14:22: error: default template argument in a class template partial specialization
typename = std::enable_if_t<std::is_arithmetic<dtype>::value> >
^
./includes/helpers.hpp:16:8: error: class template partial specialization contains a template parameter that cannot be deduced; this partial specialization will never be used [-Wunusable-partial-specialization]
struct hash<std::vector<dtype> >
^~~~~~~~~~~~~~~~~~~~~~~~~
我尝试尽可能地遵循不同的 enable_if_t 指南。但它似乎不起作用,我做错了什么?
它似乎在不使用 enable_if_t 的情况下工作。但是这样可能会与不应使用此散列的 vector 发生冲突
这是我到目前为止的代码(经过编辑更“完整”)
#include <iostream>
#include <type_traits>
#include <vector>
namespace std {
template <typename dtype,
typename = std::enable_if_t< std::is_arithmetic<dtype>::value> >
struct hash<std::vector<dtype> > {
size_t operator()(const std::vector<dtype> &input)
{
//perform hash
}
};
}
using namespace std;
int main()
{
const vector<int> i{1,2,3,4};
cout << hash<vector<int>>()(i) << endl;
return 0;
}
最佳答案
问题是,std::hash
只有一个模板参数,您不能在偏特化中添加额外的默认模板参数。因此,您有多种选择,具体取决于您要对哈希执行的操作。
也请重新考虑您的方法。这comment by Yakk非常有用:
You may not specialize templates in std unless the specialization depends on a user-provided type. – Yakk
您可以通过不将自己的 hash
放入 std
命名空间来轻松解决此问题。
您可以简单地从模板参数列表中删除
enable_if
并将其替换为static_assert(std::is_arithmetic<dtype>::value, "!");
在结构体中,假定您只想散列算术类型的 vector 。
调用运营商的 SFINAE。这样,您必须为同一结构中的所有其他 vector 类型提供所有哈希方法。此外,您还必须经历一些有趣的事情,即重复模板参数以使编译器满意。您的 SFINAE 标准是相互排斥的,这一点非常重要,否则您会遇到可怕的错误。
#include <iostream> #include <string> #include <type_traits> #include <vector> namespace std { template< typename dtype > struct hash< std::vector<dtype> > { template< typename T = dtype > std::enable_if_t<std::is_arithmetic<T>::value, size_t> operator()(const std::vector<T> &input) const { constexpr size_t FNV_prime = 1099511628211ul; constexpr size_t FNV_offset = 14695981039346656037ul; size_t hashed = FNV_offset; for(const auto &n:input) { hashed ^= n; hashed *= FNV_prime; } return hashed; } template< typename T = dtype > std::enable_if_t<!std::is_arithmetic<T>::value, size_t> operator()(const std::vector<T> &input) const { std::cout << "No hash for you :-(\n"; return 0; } }; } // namespace std int main() { { std::vector<int> v{1,2,3,4}; size_t hash = std::hash<std::vector<int>>{}(v); std::cout << hash << "\n"; } { std::vector<std::string> v{"Hello", "world!"}; size_t hash = std::hash<std::vector<std::string>>{}(v); std::cout << hash << "\n"; } }
您还可以声明自己的散列结构,并根据需要添加任意数量的模板参数。然后你只需要
std::hash
来继承你的自定义结构。#include <iostream> #include <string> #include <type_traits> #include <vector> template < typename T, bool = std::is_arithmetic<T>::value > struct vector_hash; template < typename T> struct vector_hash<T,true> { size_t operator()(std::vector<T> const &input) const { constexpr size_t FNV_prime = 1099511628211ul; constexpr size_t FNV_offset = 14695981039346656037ul; size_t hashed = FNV_offset; for(const auto &n:input) { hashed ^= n; hashed *= FNV_prime; } return hashed; } }; template < typename T> struct vector_hash<T,false> { size_t operator()(std::vector<T> const &) const { std::cout << "No hash for you :-(\n"; return 0; } }; namespace std { template< typename dtype > struct hash< std::vector<dtype> > : vector_hash<dtype> {}; } // namespace std int main() { { std::vector<int> v{1,2,3,4}; size_t hash = std::hash<std::vector<int>>{}(v); std::cout << hash << "\n"; } { std::vector<std::string> v{"Hello", "world!"}; size_t hash = std::hash<std::vector<std::string>>{}(v); std::cout << hash << "\n"; } }
关于c++ - 特定 type_trait vector 的类特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47964496/