特定type_trait向量的类的专门化

问题描述 投票:0回答:2

我正在尝试将hash专门化为包含所有算术类型的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的情况下工作。但是,与不应该使用此哈希的向量可能存在冲突

到目前为止这是我的代码(编辑为更“完整”)

#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;
}
c++ templates vector template-specialization
2个回答
1
投票

问题是,std::hash只有一个模板参数,你不能在部分特化中添加额外的默认模板参数。因此,您有多种选择,具体取决于您对哈希的处理方式。

还请重新考虑您的方法。这个comment by Yakk非常有用:

除非专门化取决于用户提供的类型,否则您可能不会在std中专门化模板。 - Yakk

您可以通过不将自己的hash放入std命名空间来轻松解决此问题。

  1. 您可以简单地从模板参数列表中删除enable_if并将其替换为 static_assert(std::is_arithmetic<dtype>::value, "!"); 在struct体中,假设您只想要算术类型的哈希向量。
  2. 呼叫运营商的SFINAE。这样,您必须为同一结构中的所有其他向量类型提供所有哈希方法。此外,你必须经历一些重复模板参数的有趣业务,以使编译器满意。您的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"; } } Live example
  3. 您还可以声明自己的哈希结构,并根据需要添加任意数量的模板参数。然后你只需要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"; } } Live example

1
投票

在命名空间std中专门化模板是非法的,除非您在用户提供的类型上执行此操作。矢量不是用户提供的。

你需要做的是:

namespace helper{
  template<class T, class=void>
  struct hash:std::hash<T>{};
}

现在你可以用助手的哈希做普通的sfinae技巧,或者不加考虑地扩展它。

namespace helper {
  template <typename dtype>
  struct hash<std::vector<dtype>,
     std::enable_if_t< std::is_arithmetic<dtype>::value> 
  > {
    size_t operator()(const std::vector<dtype> &input) const {
        //perform hash
    }
  };
}

只需通过helper::hash<T>代替std hash。额外的void默认参数允许sfina专门化,基本规范转发std哈希,并且没有不良形式问题。

© www.soinside.com 2019 - 2024. All rights reserved.