c++ - 特定 type_trait vector 的类特化

标签 c++ templates vector template-specialization

我正在尝试专门化哈希以包括所有算术类型的 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 命名空间来轻松解决此问题。

  1. 您可以简单地从模板参数列表中删除 enable_if 并将其替换为

    static_assert(std::is_arithmetic<dtype>::value, "!");
    

    在结构体中,假定您只想散列算术类型的 vector 。

  2. 调用运营商的 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";
        }
    }
    

    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

关于c++ - 特定 type_trait vector 的类特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47964496/

相关文章:

c++ - UMDF 驱动程序是否可以写入文件?

r - 测试单个数值向量的所有元素之间的相等性

c++ - 如何在 OpenCV 中过滤由重叠圆圈构成的轮廓

c++ - 将 0,1,2,...,N-1 作为参数传递给函数

c++ - 可变模板化结构/boost::variant 是如何实现的

c++ - 通过标准算法。模板推导

c++ - 在 C++ 中将 vector.size() 与 string.length() 相乘的意外答案

android - Lollipop 设备上的矢量可绘制渲染问题 (API22)

c++ - C++ 标准中最令人惊讶的元素是什么?

c++ - 通过指针转换将右值绑定(bind)到非常量引用?