如何使boost unordered_map支持flyweight<string>?

10

我正在尝试做以下事情:

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> > map;

        boost::flyweight<std::string> foo(name);
        map[foo] = foo;

但是编译器报错:“error C2665: 'boost::hash_value' : none of the 17 overloads could convert all the argument types”。

但是我已经定义了下面的函数:

std::size_t hash_value(const boost::flyweight<std::string> & b)
{
    boost::hash<std::string> hasher;
    const std::string & str = b.get();
    return hasher(str);
}
bool operator==(const boost::flyweight<std::string>& f, const boost::flyweight<std::string> & second)
{
    return f.get() == second.get();
}

但是它无法编译。

我需要做什么来让boost unordered_map支持flyweight?

[编辑] 我使用以下代码使其工作:

    struct flyweight_hash
    {
        std::size_t operator()(const boost::flyweight<std::string> &elm) const
        {
            boost::hash<std::string> hasher;
            const std::string & str = elm.get();
            return hasher(str);
        }
    };

将其作为模板参数传递给map的构造函数:

boost::unordered_map<boost::flyweight<std::string>, boost::flyweight<std::string> , flyweight_hash > map;
在这种情况下,我不明白为什么重载 hash_value 没有起作用。
2个回答

7

boost::hash通过参数依赖查找(ADL)调用hash_value函数。你试图为命名空间boost中的类定义一个hash_value函数。因此,你的hash_value函数也需要放入这个命名空间才能使ADL正常工作。不幸的是,将函数添加到外部命名空间是相当恶劣的行为,应该避免。使用自定义哈希器的解决方案是可行的。

以下是一个小例子以说明:

namespace boost {
  // somewhere in boost
  template<typename T>
  std::size_t hash(const T& t) { 
    // call using ADL
    // e.g. if called with object of class type foo::bar this will
    // pick up foo::hash_value despite the lack of namespace
    // qualification
    return hash_value(t); 
  }
}

// your hash_value (presumably in the global namespace)
// not picked up by above call
std::size_t hash_value(boost::flyweight<T>...);

namespace boost {
  // this would be picked up but is slightly evil
  std::size_t hash_value(boost::flyweight<T>...);
}

只是因为 boost::unordered_map 的默认哈希函数似乎没有通过 using boost::hash_value; return hash_value(key); 触发 ADL,所以它才不好。不过我现在无法检查。 - Xeo
@Xeo 默认哈希函数应该是 boost::hash,而不应该特定于 unordered_map。至少文档是这样说的。 - pmr
当然可以,但这并不改变启用ADL的调用似乎没有被使用的事实。 - Xeo
@Xeo,ADL如何能够找到示例中显示的“hash_value”?“flyweight”在命名空间“boost”中,该命名空间中没有匹配的重载项,而命名空间外部的重载项也不会被考虑。除非OP实际上在该命名空间中定义了他的“hash_value”,但我怀疑这一点。 - pmr
哦,没事了..别理我,我在这里有点困惑。 :| - Xeo
@Xeo 我添加了一些示例代码,以使事情更加清晰。 - pmr

7

对已经被哈希过的内容再次进行哈希是一种浪费。 单纯享元模式会维护相等对象的单个实例,因此哈希这个实例的地址而不是其内容会更加高效。 我按照以下步骤进行操作(在std中,而不是在boost中,因为我使用的是C++11,所以我正在扩展std :: hash ,而不是 boost :: hash ):

namespace std
{
  template <typename T>
  struct hash<boost::flyweight<T, boost::flyweights::no_tracking>>
  {
    using value_type = boost::flyweight<T, boost::flyweights::no_tracking>;
    size_t operator()(const value_type& ss) const
    {
      hash<const void*> hasher;
      return hasher(&ss.get());
    }
  };
}

我已确认这是设计上的工作,而不是意外发生的:http://lists.boost.org/boost-users/2013/03/78007.php


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接