C++11 我应该将用户定义类型的专用std::hash放在哪里

C++11 我应该将用户定义类型的专用std::hash放在哪里,c++11,hash,unordered-set,user-defined,C++11,Hash,Unordered Set,User Defined,我搜索了很多页面,我想我已经知道如何编写std::hash。但我不知道该把它放在哪里 这里给出了一个例子 但是,我在文件Instance\u management.h的命名空间ca中定义了我的类型Instance。我想在另一个类的同一个文件中使用InstanceManager。因此,我编写了以下代码: namespace std { template <> struct hash<ca::Instance> { size_t operato

我搜索了很多页面,我想我已经知道如何编写std::hash。但我不知道该把它放在哪里

这里给出了一个例子

但是,我在文件
Instance\u management.h
的命名空间
ca
中定义了我的类型
Instance
。我想在另一个类的同一个文件中使用
InstanceManager
。因此,我编写了以下代码:

namespace std
{
    template <> struct hash<ca::Instance>
    {
        size_t operator()(const ca::Instance & instance) const
        {
            std::size_t seed = 0;
            // Some hash value calculation here.
            return seed;
        }
    };
} // namespace std
名称空间std
{
模板结构哈希
{
size\u t运算符()(常量ca::实例和实例)常量
{
std::size\u t seed=0;
//这里有一些散列值计算。
返回种子;
}
};
}//名称空间std
但是我应该把它放在哪里呢?我尝试了很多地方,但都失败了

我正在使用visual studio 2013。我试图将前面的代码放在一些位置,但都未能编译

// location 1

namespace ca
{
    class Instance {...}
    class InstanceManager
    {
        // ... some other things.
        private unordered_set<Instance>;
    }
}

// location 2
//位置1
命名空间ca
{
类实例{…}
类实例管理器
{
//…还有其他一些事情。
私有无序集;
}
}
//地点2

不要专门研究
std::hash
,而是编写自己的hash函数对象(请参见下面的
Edge\u hash
),并使用两个模板参数声明您的
无序集

#include <unordered_set>
#include <functional>

namespace foo
{
    // an edge is a link between two nodes
    struct Edge
    {
        size_t src, dst;
    };

    // this is an example of symmetric hash (suitable for undirected graphs)
    struct Edge_Hash
    {
        inline size_t operator() ( const Edge& e ) const
        {
            static std::hash<size_t> H;
            return H(e.src) ^ H(e.dst);
        }
    };

    // this keeps all edges in a set based on their hash value
    struct Edge_Set
    {
        // I think this is what you're trying to do?
        std::unordered_set<Edge,Edge_Hash> edges;
    };
}

int main()
{
    foo::Edge_Set e;
}
#包括
#包括
名称空间foo
{
//边是两个节点之间的链接
结构边
{
尺寸src,dst;
};
//这是对称散列的一个示例(适用于无向图)
结构边散列
{
内联大小\u t运算符()(常数边和e)常数
{
静态std::hash H;
返回H(e.src)^H(e.dst);
}
};
//这将根据其哈希值将所有边保留在一个集中
结构边集合
{
//我想这就是你想做的?
std::无序的集合边;
};
}
int main()
{
foo::边集e;
}
相关职位包括:


  • 有几种方法

    专门化
    std::hash
    在代码中,确保
    std::hash
    专门化前面紧跟着
    实例
    类定义,后面紧跟着使用它的
    无序集
    容器

    namespace ca
    {
        class Instance {...};
    
    }
    
    namespaces std {
    
        template<> hash<Instance> { ... };
    
    }
    
    namespace ca {
    
        class InstanceManager
        {
            // ... some other things.
            private unordered_set<Instance>;
        }
    }
    
    在这里,您只需将自己的哈希函数传递给容器,然后就可以使用它了。缺点是您必须显式地键入自己的容器

    使用
    hash\u append
    然而,请注意,标准提案目前尚待审查。该方案的特点是采用了一种更优越的设计,即使用一个通用哈希函数,该函数通过模板参数(实际的哈希算法)对任意字节流进行哈希

    有关更多详细信息,请参阅作者@HowardHinnant在CppCon14(,)上的演示。和提供的完整源代码。

    谢谢大家

    我找到了原因并以某种方式解决了问题:当我定义
    实例时,visual studio接受了
    实例哈希
    。由于我正在将
    set
    的用法更改为
    unordered\u set
    ,因此在尝试获取
    const\u迭代器时,我忘记了指定
    InstanceHash
    ,所以这次编译器尝试使用
    std::hash
    东西,但失败了。但是编译器没有使用
    const\u迭代器
    定位该行,因此我在定义
    实例时错误地认为它不接受
    InstanceHash

    我还尝试专门化类实例的
    std::hash
    。但是,这种专门化至少需要声明class
    ca::Instance
    及其一些成员函数来计算散列值。经过此专门化之后,类
    ca::InstanceManage
    的定义将使用它


    我现在通常把几乎所有类和成员函数的声明和实现放在一起。所以,我需要做的是把<代码> CA<代码>代码命名空间范围分成2个部分,并在中间放置“代码> STD{StuttHuth{H.{}} /Cuth.<我的C++代码库。因此,instance_management.h文件中没有main()。我必须尝试将所有内容放在名称空间中,包括类实例和使用无序_集的InstanceManager。然而,许多页面上都说,鼓励在std名称空间中为用户定义的类型放置专门的std::hash。我编写了代码片段,并试图将其放在同一文件中的某个位置,但未能成功编译instance_management.h文件。当我将您的代码放在单独的.h文件中时,visual studio成功编译了它。然而,当我用同样的方法编写代码并使用“private:unordered\u set instances”时,我得到的错误是:像:<代码>错误C23 38:C++标准不提供这种类型的哈希。<代码> >代码>参见引用类模板实例化“STD::Hash”被编译1 > 1 > [ 1>KKTY=CA:实例1 > ] />代码>。编译器似乎不接受我指定的InstanceHash。将其放入
    实例管理.h
    有什么错?我会向上投票+10,因为这太棒了,但它并没有真正回答OP是否接受它?@Sh3ljohn有工作代码实现了这一点,并完全避免使用
    std::hash
    。在你的回答中,陈述
    H(e.src)^H(e.dst)
    是薄弱环节。它可能会破坏哈希函数的所有好属性。@TemplateRex实际上,我不知道“标准建议”是什么意思。这是否意味着某一天的提案将是C++标准?编译器支持如何?VC++会支持它吗?@TemplateRex我尝试了
    使用std::hash\u append,然后按
    F1
    键进行
    hash\u append
    。联机文档系统未找到有关的信息
    struct MyInstanceHash { ... };
    
    using MyUnorderedSet = std:unordered_set<Instance, MyInstanceHash>;
    
    template <class HashAlgorithm>
    struct uhash
    {
        using result_type = typename HashAlgorithm::result_type;
    
        template <class T>
        result_type
        operator()(T const& t) const noexcept
        {
            HashAlgorithm h;
            using std::hash_append;
            hash_append(h, t);
            return static_cast<result_type>(h);
        }
    };
    
    class X
    {
        std::tuple<short, unsigned char, unsigned char> date_;
        std::vector<std::pair<int, int>>                data_;
    
    public:
        // ...
        friend bool operator==(X const& x, X const& y)
        {
            return std::tie(x.date_, x.data_) == std::tie(y.date_, y.data_);
        }
    
        // Hook into the system like this
        template <class HashAlgorithm>
        friend void hash_append(HashAlgorithm& h, X const& x) noexcept
        {
            using std::hash_append;
            hash_append(h, x.date_);
            hash_append(h, x.data_);
        }
    }