2015-09-26 12 views
10

は、私はクラスの内部で定義された列挙型を持っている、と私はクラスのメンバーとしてそれらのオブジェクトのunordered_setを作成したい:今すぐクラス内で定義されたenumのstd :: hashをオーバーライドする方法は?

#include <unordered_set> 

class Foo { 
public: 
    enum Bar { 
    SOME_VALUE 
    }; 

    // Error: implicit instantiation of std::hash 
    std::unordered_set<Bar> getValues() const { 
    return _values; 
    } 

private: 
    std::unordered_set<Bar> _values; 
}; 

、私は明白な答えは追加することです知っていますunordered_setにカスタムハッシュ関数は:unordered_mapを使用するすべてのユーザーが自動的にハッシュの挙動を取得するようにバーの列挙型のためのstd ::ハッシュを専門とする方法があるかどう

std::unordered_set<Bar, BarHasher> 

しかし、私が思ったんだけどすることです。

これは、他のすべてのデータ型で動作しますが、列挙型ではありません。列挙型を宣言して転送することはできません。

これを行うには、std :: hashの定義をenum定義の後に置かなければならないが、最初の使用の前には、クラスの真ん中に置く必要がある体、それは動作しません。

+0

列挙型を宣言することはできますが、どのように役立つかはわかりません。 – chris

+1

これはC++ 14で修正されています:http://stackoverflow.com/a/29618545/951890 –

答えて

3

しかし、私が思ったんだけどすることです。

奇跡はありませんので、誰でも特化したstd::hashを使用します。別のクラスの中でクラスを特殊化することはできず、その列挙型はネストされているので、クラス内にstd::hashを使用するのが問題になります。列挙型を指摘しているように、宣言することはできません。したがって、クラス内に特殊なstd::hashを使用する唯一の解決策(ベースクラスまたは "ネストされていない"列挙型を作成せずに):参照によって集約/宣言し、std::hash特化後に外部で使用する唯一のソリューションがあります。

#include <iostream> 
#include <unordered_set> 
#include <memory> 

struct A { 

    enum E { 
     first, second 
    }; 

    A(); 

    std::unique_ptr< std::unordered_set<E> > s_; //!< Here is 
}; 

namespace std { 

template<> 
class hash<A::E> { 
public: 
    std::size_t operator()(A::E const& key) const noexcept { 
     std::cout << "hash<A::E>::operator()" << std::endl; 
     return key; 
    } 

}; 

} 

A::A() 
    : s_(new std::unordered_set<E>) 
{ } 

int main(void) { 
    A a; 
    a.s_->insert(A::first); 

    std::unordered_set<A::E> s; 
    s.insert(A::second); 
} 

プリントアウト

ハッシュ< A :: E> ::演算子()
ハッシュ< A :: E> ::演算子()

したがって、外部クラスAは誰でもstd::hashA::Eを使用することができ、内部クラスとしてA::Estd::hashを使用することもできます。また、参照としてstd::unordered_setを集計したくない場合は、内部使用のみのカスタムハッシャーを実装してから、std::hashコールを転送することもできます。

1

あなたはあなたの質問にすでにすべての角度をカバーしたようです。

私はこれを行う方法を考えることはできません。要約すると

、あなただけの状況の事実を変更することができます。

  • 明示のように調理人の機能を使用しenumは、非入れ子になった(代わりに囲まれた名前空間に入れて)作る、または
  • あなたの例。
3

1つの可能性は、列挙型を基本クラスに入れることです。残念なことに、各enumメンバーに対してuse宣言を提供する必要があります。その周りの1つの方法は、Foo::SOME_VALUEの代わりにFoo::Bar::SOME_VALUEのような使用が必要なスコープ付き列挙型(enum class Bar)を使用することです。これを行うには、using FooBase::Bar;が必要です。 unordered_mapを使用するすべてのユーザーが自動的にハッシュの挙動を取得するようにバーの列挙型のためのstd ::ハッシュを専門とする方法があるかどう

class FooBase { 
public: 
    enum Bar { 
    SOME_VALUE 
    }; 

protected: 
    ~FooBase() = default; //so can't be used polymorphically 
}; 

//hash goes here 

class Foo : FooBase { 
public: 
    using FooBase::Bar; 
    using FooBase::SOME_VALUE; 
    ... 
+0

これは発明的です。私はそれを使用しないだろうが、私は笑った。 :) –

関連する問題