c++ - 构建以元组为键的无序映射

标签 c++ boost tuples unordered-map

在带有 Boost 的 C++ 程序中,我正在尝试构建一个无序映射,其键是 double 元组:

typedef boost::tuples::tuple<double, double, double, double> Edge;
typedef boost::unordered_map< Edge, int > EdgeMap;

初始化 map 可以完成,但是,当我尝试用键和值填充它时

EdgeMap map;
Edge key (0.0, 0.1, 1.1, 1.1);
map[key] = 1;

我遇到以下错误消息:

/usr/include/boost/functional/hash/extensions.hpp:176: error: no matching function for call to ‘hash_value(const boost::tuples::tuple<double, double, double, double, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>&)’

我认为这是因为我需要为元组键指定一个哈希函数。我该怎么做?

编辑:

根据以下建议,我编写了以下实现:

#include <boost/tuple/tuple.hpp>
#include <boost/unordered_map.hpp>

typedef boost::tuples::tuple<double, double, double, double> Edge;

struct ihash
    : std::unary_function<Edge, std::size_t>
{
    std::size_t operator()(Edge const& e) const
    {
        std::size_t seed = 0;
        boost::hash_combine( seed, e.get<0>() );
        boost::hash_combine( seed, e.get<1>() );
        boost::hash_combine( seed, e.get<2>() );
        boost::hash_combine( seed, e.get<3>() );
        return seed;
    }
};

struct iequal_to
    : std::binary_function<Edge, Edge, bool>
{
    bool operator()(Edge const& x, Edge const& y) const
    {
        return ( x.get<0>()==y.get<0>() &&
                 x.get<1>()==y.get<1>() &&
                 x.get<2>()==y.get<2>() &&
                 x.get<3>()==y.get<3>());
    }
};

typedef boost::unordered_map< Edge, int, ihash, iequal_to > EdgeMap;

int main() {

    EdgeMap map;
    Edge key (0.0, 0.1, 1.1, 1.1);
    map[key] = 1;

    return 0;
}

可以缩短吗?

最佳答案

实际上,您可以完美地为 boost::tuple 定义一个通用哈希函数。唯一的要求是它位于同一个命名空间中,以便被 ADL 拾取。

我真的很惊讶他们还没有写一个。

namespace boost { namespace tuples {

  namespace detail {

    template <class Tuple, size_t Index = length<Tuple>::value - 1>
    struct HashValueImpl
    {
      static void apply(size_t& seed, Tuple const& tuple)
      {
        HashValueImpl<Tuple, Index-1>::apply(seed, tuple);
        boost::hash_combine(seed, tuple.get<Index>());
      }
    };

    template <class Tuple>
    struct HashValueImpl<Tuple,0>
    {
      static void apply(size_t& seed, Tuple const& tuple)
      {
        boost::hash_combine(seed, tuple.get<0>());
      }
    };
  } // namespace detail

  template <class Tuple>
  size_t hash_value(Tuple const& tuple)
  {
    size_t seed = 0;
    detail::HashValueImpl<Tuple>::apply(seed, tuple);
    return seed;
  }

} }

注意:我只是证明它是正确的,我没有测试过。

关于c++ - 构建以元组为键的无序映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3611951/

相关文章:

Scala - 元组类型推断失败?

c++ - 未解析为候选容器的模板运算符模板

c++ - 使用pugixml将xml namespace 添加到xml_document

c++ - 属性传播到嵌套映射

c++11 - 通过删除叶子来制作 boost 图的子图

c# - 我可以将 ValueTuple 传递给需要泛型类型的方法并仍然维护成员变量吗?

c++ - 如果系统内存足够,C++ 字符串是否可以包含无限数量的字符,并且 size_t 可以表示如此极端的长度吗?

c++ - Visual Studio 2012 C++ 如何在 NMake 项目中添加编译器选项

c++ - 在 Eclipse(或 Xcode)中链接 Boost 程序选项

c# - 在 C# 中查找和删除元组列表中的重复项