• 在c++11 的unordered_set和unordered_map中插入pair或tuple作为键值


    参考:https://blog.csdn.net/pineappleKID/article/details/108341064

    想完成的任务 与 遇到的问题
    想在c++11 的unordered_set和unordered_map中插入pair或tuple作为键值

    std::unordered_map<std::pair<std::string,std::string>, int> m;
    
    • 1

    会报错
    /usr/include/c++/4.9/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash, std::hash > >’
    或者
    /usr/include/c++/4.9/bits/hashtable_policy.h: In instantiation of ‘struct std::__detail::__is_noexcept_hash, std::hash > >’
    C++的std::pair是无法std::hash的,为了在unordered_set和unordered_map中使用std::pair,有如下方法。还有个前提,pair 和 tuple 中的元素本身得是可以 std::hash 哈希的。

    方法一:专门写个可用于std::pair的std::hash

    #include 
    #include 
    #include 
    
    typedef std::pair<std::string,std::string> pair;
    
    struct pair_hash
    {
    	template <class T1, class T2>
    	std::size_t operator() (const std::pair<T1, T2> &pair) const
    	{
    		return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
    	}
    };
    
    int main()
    {
    	std::unordered_map<pair,int,pair_hash> unordered_map =
    	{
    		{{"C++", "C++11"}, 2011},
    		{{"C++", "C++14"}, 2014},
    		{{"C++", "C++17"}, 2017},
    		{{"Java", "Java 7"}, 2011},
    		{{"Java", "Java 8"}, 2014},
    		{{"Java", "Java 9"}, 2017}
    	};
    
    	for (auto const &entry: unordered_map)
    	{
    		auto key_pair = entry.first;
    		std::cout << "{" << key_pair.first << "," << key_pair.second << "}, "
    				  << entry.second << '\n';
    	}
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    输出

    {Java,Java 8}, 2014
    {Java,Java 7}, 2011
    {Java,Java 9}, 2017
    {C++,C++17}, 2017
    {C++,C++14}, 2014
    {C++,C++11}, 2011
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意:上面的代码使用的异或(XOR),由于x^x == 0并且x^y == y^x,所以应该配合一些位运算的shift或rotate来做。

    方法二:使用boost::hash
    boost::hash可以用于哈希integers, floats, pointers, strings, arrays, pairs 以及其它 STL 里的东西

    #include 
    #include 
    #include 
    #include 
    
    typedef std::pair<std::string,std::string> pair;
    
    int main()
    {
    	std::unordered_map<pair,int,boost::hash<pair>> unordered_map =
    	{
    		{{"C++", "C++11"}, 2011},
    		{{"C++", "C++14"}, 2014},
    		{{"C++", "C++17"}, 2017},
    		{{"Java", "Java 7"}, 2011},
    		{{"Java", "Java 8"}, 2014},
    		{{"Java", "Java 9"}, 2017}
    	};
    
    	for (auto const &entry: unordered_map)
    	{
    		auto key_pair = entry.first;
    		std::cout << "{" << key_pair.first << "," << key_pair.second << "}, "
    				  << entry.second << '\n';
    	}
    
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    输出

    {Java,Java 8}, 2014
    {Java,Java 9}, 2017
    {Java,Java 7}, 2011
    {C++,C++17}, 2017
    {C++,C++14}, 2014
    {C++,C++11}, 2011
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注意:boost的hash的位置改过,有网友说boost 1.72的hash在

    #include 
    
    
    • 1
    • 2

    原话是

    By the way the functional hash has moved. I am not sure when, but in boost 1.72 it is in #include I am not sure why the boost hash function for a tuple is not documented somewhere.

    方法三:hash_combine
    把下列代码放在任何你想实现本文目的代码头文件里
    原话是

    This works on gcc 4.5 allowing all c++0x tuples containing standard hashable types to be members of unordered_map and unordered_set without further ado. (I put the code in a header file and just include it.)
    The function has to live in the std namespace so that it is picked up by argument-dependent name lookup (ADL).

    #include 
    namespace std{
        namespace
        {
    
            // Code from boost
            // Reciprocal of the golden ratio helps spread entropy
            //     and handles duplicates.
            // See Mike Seymour in magic-numbers-in-boosthash-combine:
            //     http://stackoverflow.com/questions/4948780
    
            template <class T>
            inline void hash_combine(std::size_t& seed, T const& v)
            {
                seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
            }
    
            // Recursive template code derived from Matthieu M.
            template <class Tuple, size_t Index = std::tuple_size<Tuple>::value - 1>
            struct HashValueImpl
            {
              static void apply(size_t& seed, Tuple const& tuple)
              {
                HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
                hash_combine(seed, std::get<Index>(tuple));
              }
            };
    
            template <class Tuple>
            struct HashValueImpl<Tuple,0>
            {
              static void apply(size_t& seed, Tuple const& tuple)
              {
                hash_combine(seed, std::get<0>(tuple));
              }
            };
        }
    
        template <typename ... TT>
        struct hash<std::tuple<TT...>> 
        {
            size_t
            operator()(std::tuple<TT...> const& tt) const
            {                                              
                size_t seed = 0;                             
                HashValueImpl<std::tuple<TT...> >::apply(seed, tt);    
                return seed;                                 
            }                                              
    
        };
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
  • 相关阅读:
    遇到的题目
    播放视频出现错误代码0xc00d36c4如何修复?
    AI绘图之Midjourney初体验
    Rock Pi开发笔记(二):入手Rock Pi 4B plus(基于瑞星微RK3399)板子并制作系统运行
    c++视觉--通道分离,合并处理,在分离的通道中的ROI感兴趣区域里添加logo图片
    go实现N个协程交替顺序打印自然数的详细解释
    数仓:数仓从ETL到ELT架构的转化以及俩者的区别
    循环队列(出队、入队、判空、长度、遍历、取头)(数据结构与算法)
    分享几个源码网站奉献给大家(持续更新中……)
    【TensorRT】PyTorch模型转换为ONNX及TensorRT模型
  • 原文地址:https://blog.csdn.net/qq_21237549/article/details/136219426