如何让boost unordered_map支持flyweight

发布于 2024-12-23 16:49:29 字数 1319 浏览 2 评论 0原文

我正在尝试执行以下操作:

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

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

但编译器抱怨: “错误 C2665:'boost::hash_value':17 个重载中没有一个可以转换所有参数类型”。

但我定义了以下函数:

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);
        }
    };

并将其作为模板参数传递给地图的构造:

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

在这种情况下,我不明白重载 hash_value 不起作用的方式。

I am trying to do the following:

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

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

But the compiler complains:
"error C2665: 'boost::hash_value' : none of the 17 overloads could convert all the argument types".

But I have defined the following function:

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();
}

But it doesn´t compile.

What do I need to do to make boost unordered_map to support flyweight?

[EDIT]
I got it to work with the following code:

    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);
        }
    };

and passed it as a template parameter to the construction of the map:

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

In this case I don´t understand way overloading hash_value didn´t worked.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

小傻瓜 2024-12-30 16:49:29

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::hash calls hash_value through argument dependent lookup (ADL). You are trying to define a hash_value function for a class in namespace boost. Hence your hash_value function would need to go into this namespace as well for ADL to work. Unfortunately, adding functions to a foreign namespace is rather evil and should be avoided. Your solution of using a custom hasher seems fine.

A little example code to illustrate:

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>...);
}
甜心小果奶 2024-12-30 16:49:29

对已经被散列过的东西进行散列是很遗憾的。 Flyweight 保留相等对象的单个实例,因此散列该实例的地址而不是其内容更有效。我执行如下操作(在 std 中,而不是在 boost 中,因为我使用的是 C++11,所以我扩展了 std::hash code>,而不是 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

It is a pity to hash something which has already been hashed. Flyweight keeps a single instance of equal objects, so it is more efficient to hash the address of this instance, instead of its content. I do as follows (in std, not in boost, as I'm using C++11, so I'm extending std::hash, not 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());
    }
  };
}

I have been confirmed that this works by design, not by accident: http://lists.boost.org/boost-users/2013/03/78007.php

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文