Как сделать boost unordered_map для поддержки flyweight <string> - PullRequest
10 голосов
/ 02 января 2012

Я пытаюсь сделать следующее:

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

Но он не компилируется.

Что мне нужно сделать, чтобы повысить unordered_map для поддержки flyweight?

[EDIT] Я получил его для работы со следующим кодом:

    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 не сработала.

Ответы [ 2 ]

7 голосов
/ 02 января 2012

boost::hash вызывает hash_value через зависимый от аргумента поиск (ADL). Вы пытаетесь определить функцию hash_value для класса в пространстве имен boost. Следовательно, ваша 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>...);
}
5 голосов
/ 06 марта 2013

Жалко хешировать то, что уже хешировано.Flyweight хранит один экземпляр одинаковых объектов, поэтому эффективнее хешировать адрес этого экземпляра, а не его содержимое.Я делаю следующее (в 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

...