4

絞り込むには:現在、Boost.Unorderedを使用しています。私は2つの可能な解決策を見ます:

  1. 独自の等式述語とハッシュ関数を定義し、テンプレート(多分is_pointer)を利用してポインターとインスタンスを区別します。

  2. ハッシュに関してboost::hash提供することによって単に拡張するために; 等価性チェックの場合と同様に、パラメーターを使用したフリー関数として演算子のオーバーロードhash_value(Type* const& x)を追加します。==(Type* const& x, Type* const& y)

私はそれらをテストしなかったので、両方のバリエーションが実際に可能かどうかはわかりません。あなたがこの問題を処理していることを知りたいと思います。実装は大歓迎です:)

編集1: これはどうですか?

template<class T>
struct Equals: std::binary_function<T, T, bool> {
    bool operator()(T const& left, T const& right) const {
        return left == right;
    }
};

template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
    bool operator()(T* const& left, T* const& right) const {
        return *left == *right;
    }
};

編集2:

私はちょうど定義しました:

friend std::size_t hash_value(Base const& base) {
    boost::hash<std::string> hash;

    return hash(base.string_);
}

friend std::size_t hash_value(Base* const& base) {
    return hash_value(*base);
}

その後:

Derived d1("x");
Derived d2("x");

unordered_set<Base*> set;

set.insert(&d1);

assert(set.find(&d2) == end());

デバッガーは、それが呼び出されることfriend std::size_t hash_value(Base* const& base)はないと言います(GCC4.7)。何故ですか?

編集3:行#215(Boost 1.49)は、Boostのポインターの特殊化であり、 EDIT2の私のようなカスタム実装を単純にマスクしていることtemplate <class T> std::size_t hash_value(T* const& v)が わかりました。したがって、ここでの唯一の方法は、カスタムハッシュファンクターを作成することのようです。boost/functional/hash.hpphash_value

4

2 に答える 2

5

ハッシュ関数については、特殊化boost::hash(またはstd::hash新しい標準) するか、新しいファンクター クラスを定義するかを選択できます。これらの代替手段は同じように機能します。

等値演算子については、ポインターに対して等値演算子を再定義できないため、新しいファンクターを定義する必要があります。これは組み込み演算子 (関数用語で として定義bool operator==( T const *x, T const *y )) であり、置き換えることはできません。

これらは両方とも、テンプレートoperator()化されていないクラスでテンプレート化されたものを使用して一般的に定義できます。

struct indirect_equal {
    template< typename X, typename Y >
    bool operator() ( X const &lhs, Y const &rhs )
        { return * lhs == * rhs; }
};

ハッシャーについても同様のパターンに従います。

于 2012-04-08T13:15:30.133 に答える
1

元の投稿のすべての編集を考慮して、私のニーズを満たす完全なソリューションを提供したいと思います。

1. 平等:

template<class T>
struct Equal: ::std::binary_function<T, T, bool> {
    bool operator()(T const& left, T const& right) const {
        ::std::equal_to<T> equal;

        return equal(left, right);
    }
};

template<class T>
struct Equal<T*> : ::std::binary_function<T*, T*, bool> {
    bool operator()(T* const & left, T* const & right) const {
        Equal<T> equal;

        return equal(*left, *right);
    }
};

2. ハッシング:

template<class T>
struct Hash: ::std::unary_function<T, ::std::size_t> {
    ::std::size_t operator()(T const & value) const {
        ::boost::hash<T> hash;

        return hash(value);
    }
};

template<class T>
struct Hash<T*> : ::std::unary_function<T*, ::std::size_t> {
    ::std::size_t operator()(T* const & value) const {
        Hash<T> hash;

        return hash(*value);
    }
};

したがって、Boost を引き続き使用できるhash_valueようになり、Boost のデフォルトの実装によってポインター型がマスクされることはありません ( EDIT 3を参照)。

3. 例:

私のアプリケーションには、unordered_set次のような薄いラッパーがあります。

template<class T, class H = Hash<T>, class E = Equal<T> >
class Set {
public:

// code omitted...

    bool contains(const T& element) const {
        return s_.find(element) != end();
    }

    bool insert(const T& element) {
        return s_.insert(element).second;
    }

// code omitted...

private:
    ::boost::unordered::unordered_set<T, H, E> s_;
};

したがって、基本クラスがある場合:

class Base {
public:
    Base(const ::std::string& string) {
        if (string.empty())
            throw ::std::invalid_argument("String is empty.");

        string_ = string;
    }

    virtual ~Base() {
    }

    friend bool operator==(const Base& right, const Base& left) {
        return typeid(right) == typeid(left) && right.string_ == left.string_;
    }

    friend bool operator!=(const Base& right, const Base& left) {
        return !(right == left);
    }

    friend ::std::size_t hash_value(Base const& base) {
        ::boost::hash<std::string> hash;

        return hash(base.string_);
    }

    friend ::std::size_t hash_value(Base* const& base) {
        return hash_value(*base);
    }

private:
    ::std::string string_;
};

そしていくつかの派生クラス:

class Derived: public Base {
public:
    Derived(const ::std::string& string) :
            Base(string) {
    }

    virtual ~Derived() {
    }
};

次に、ポリモーフィズムを使用することもできます (ところで、これが私の主な意図でした)。

Derived d1("¯\_(ツ)_/¯");
Derived d2("¯\_(ツ)_/¯");

Set<Base*> set;

set.insert(&d1);

assert(set.contains(&d2));

お役に立てれば。どんな提案でも大歓迎です。

于 2012-04-08T18:21:09.720 に答える