10

私は次のことをしようとしています:

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を作成するには何をする必要がありますか?

[編集]次のコードで動作するようになりました:

    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のオーバーロードが機能しなかった方法がわかりません。

4

2 に答える 2

7

boost::hashhash_value引数依存ルックアップ(ADL)を介して呼び出します。hash_value名前空間のクラスの関数を定義しようとしていますboost。したがって、hash_valueADLが機能するには、関数もこの名前空間に入る必要があります。残念ながら、外部名前空間に関数を追加することはかなり悪であり、避ける必要があります。カスタムハッシャーを使用するソリューションは問題ないようです。

説明するための小さなサンプルコード:

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>...);
}
于 2012-01-01T21:30:17.660 に答える
6

すでにハッシュされているものをハッシュするのは残念です。Flyweightは、等しいオブジェクトの単一のインスタンスを保持するため、コンテンツではなく、このインスタンスのアドレスをハッシュする方が効率的です。私は次のようにします(C ++ 11を使用しているので、stdではなく、で、拡張しています):booststd::hashboost::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

于 2013-03-06T09:51:32.017 に答える