boost::unordered_map 中以结构为键的 boost 变体

Posted

技术标签:

【中文标题】boost::unordered_map 中以结构为键的 boost 变体【英文标题】:boost variant with structure as a key in boost::unordered_map 【发布时间】:2017-10-11 08:50:24 【问题描述】:

我在 boost 变体中有两个结构,variant 是 boost::unordered_map 的关键。我正在寻找实现哈希和等于方法的解决方案,该方法将采用变体中的结构。 下面是一个实现的 RouteHasher 方法(它在运行时不起作用(相同的键参数不会从映射中获取值)。如何实现一个将结构的两个成员都用于哈希的哈希?

struct v4RouteKey_t

   uint8 ipv4[4];
   uint32 val;

struct v6RouteKey_t

   uint8 ipv6[16];
   uint32 val;

typedef boost::variant < v4RouteKey_t, v6RouteKey_t > RouteKey;
typedef boost::unordered_map < RouteKey, RouteValue_t > RouteMap;

struct RouteHasher : public boost::static_visitor<std::size_t>

    template<typename T>
    std::size_t operator()(const T& x) const  return boost::hash<T>()(x); 
    std::size_t operator()(const RouteKey& x) const  return 
    boost::apply_visitor(RouteHasher(), x); 
;

struct RouteEquals : public boost::static_visitor<bool>

    template<typename T>
    bool operator()(const T& lhs, const T& rhs) const  return lhs == rhs; 

    template<typename T1, typename T2>
    bool operator()(const T1& lhs, const T2& rhs) const  return false; 

    bool operator()(const RouteKey& lhs, const RouteKey& rhs) const
     return boost::apply_visitor(RouteEquals(), lhs, rhs); 
;

【问题讨论】:

“哪个不起作用” - 为什么?编译器错误?运行时错误? 更新了帖子。 你使用的是哪个标准的c++? 【参考方案1】:

您是否为 v4RouteKey_tv6RouteKey_t 类型实现了哈希(boost::hash_valuestd::hash&lt;&gt;)和相等性?

添加使它可以为我编译:

Live On Coliru

#include <boost/unordered_map.hpp>
#include <boost/variant.hpp>
#include <boost/array.hpp>
#include <boost/tuple/tuple.hpp>
#include <cstdint>

struct v4RouteKey_t  
    boost::array<uint8_t, 4> ipv4; uint32_t val; 
    bool operator==(v4RouteKey_t const& other) const 
        return ipv4 == other.ipv4 && val == other.val;
    ;
;
struct v6RouteKey_t  
    boost::array<uint8_t, 16> ipv6; uint32_t val; 
    bool operator==(v6RouteKey_t const& other) const 
        return ipv6 == other.ipv6 && val == other.val;
    ;
;

size_t hash_value(v4RouteKey_t const& key)  return key.val; 
size_t hash_value(v6RouteKey_t const& key)  return key.val; 

struct RouteValue_t ;

typedef boost::variant<v4RouteKey_t, v6RouteKey_t> RouteKey;
typedef boost::unordered_map<RouteKey, RouteValue_t> RouteMap;

int main() 
    RouteMap map;

奖金

启用 c++17 的库/编译器可以在没有提升的情况下完成所有这些工作:

Live On Coliru

#include <unordered_map>
#include <numeric>
#include <variant>
#include <array>
#include <tuple>

struct v4RouteKey_t  
    std::array<uint8_t, 4> ipv4; uint32_t val; 

    bool operator==(v4RouteKey_t const& other) const  return std::tie(ipv4, val) == std::tie(other.ipv4, other.val); ;
;
struct v6RouteKey_t  
    std::array<uint8_t, 16> ipv6; uint32_t val; 
    bool operator==(v6RouteKey_t const& other) const  return std::tie(ipv6, val) == std::tie(other.ipv6, other.val); ;
;

namespace std 

    template <> struct hash<v4RouteKey_t> 
        size_t operator()(v4RouteKey_t const& key)  
            return std::accumulate(key.ipv4.begin(), key.ipv4.end(), size_t(key.val), [](size_t seed, uint8_t b)  return (seed*139) ^ b; );
        
    ;
    template <> struct hash<v6RouteKey_t> 
        size_t operator()(v6RouteKey_t const& key)  
            return std::accumulate(key.ipv6.begin(), key.ipv6.end(), size_t(key.val), [](size_t seed, uint8_t b)  return (seed*139) ^ b; );
        
    ;


struct RouteValue_t ;

typedef std::variant<v4RouteKey_t, v6RouteKey_t> RouteKey;
typedef std::unordered_map<RouteKey, RouteValue_t> RouteMap;

int main() 
    RouteMap map;

【讨论】:

看起来我们穿越了。您需要用 hasher 和 equals 函子来表达地图。 这是现代编译器的 stdlib-only 版本:coliru.stacked-.crooked.com/a/f56acb04035b0c93。有趣的是我不得不提供HashVariant 尽管cppreference 说它应该是标准的:en.cppreference.com/w/cpp/utility/variant/hash @RichardHodges 不是我的方法(我未能从代码 sn-p 中删除残余,现在已删除) @RichardHodges 你的意思是 Godbolt 提供了更完整的 c++17 支持:) 不,我在 UD 哈希专业化中将静态方法 hash_value 替换为 operator()

以上是关于boost::unordered_map 中以结构为键的 boost 变体的主要内容,如果未能解决你的问题,请参考以下文章

boost::boost::unordered_map 的序列化

指定构造 boost::unordered_map 时的最小桶数

如何使用 boost std::vector of boost::unordered_map 进行序列化/反序列化

boost::unordered_map() 的 find() 方法的问题

Boost::unordered_map 与初始化列表?

使用 std::map/boost::unordered_map 帮助理解段错误