2015-09-26 3 views
10

मैं एक गणना प्रकार एक वर्ग के अंदर परिभाषित मिल गया है, और मैं वर्ग के एक सदस्य के रूप में उन वस्तुओं का एक unordered_set बनाना चाहते हैं:कक्षा के अंदर परिभाषित एनम के लिए std :: हैश को ओवरराइड कैसे करें?

#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 करने के लिए कस्टम हैश फंक्शन:

std::unordered_set<Bar, BarHasher> 

हालांकि, वहाँ एक तरह से बार enum के लिए std :: हैश विशेषज्ञ ताकि जो कोई unordered_map का उपयोग करता है स्वचालित रूप से हैशिंग व्यवहार हो जाता है, तो क्या मैं सोच रहा हूँ है।

यह हर दूसरे डेटा प्रकार के साथ काम करता है, लेकिन enums नहीं - क्योंकि enums को आगे घोषित नहीं किया जा सकता है।

इस काम के लिए, मुझे enum परिभाषा के बाद std :: हैश की परिभाषा डालना होगा, लेकिन पहले उपयोग से पहले, जिसका अर्थ है कि मुझे इसे कक्षा के बीच में रखना होगा शरीर, जो काम नहीं करेगा।

+0

Enums को आगे घोषित किया जा सकता है, लेकिन मुझे नहीं लगता कि यह कैसे मदद करता है। – chris

+1

यह सी ++ 14 में तय किया गया है: http://stackoverflow.com/a/29618545/951890 –

उत्तर

3

हालांकि, वहाँ एक तरह से बार enum के लिए std :: हैश विशेषज्ञ ताकि जो कोई unordered_map का उपयोग करता है स्वचालित रूप से हैशिंग व्यवहार हो जाता है, तो क्या मैं सोच रहा हूँ है।

कोई चमत्कार नहीं है, इसलिए कोई भी विशेषज्ञता के बाद ही विशेष std::hash का उपयोग करेगा। चूंकि आप किसी अन्य वर्ग के भीतर कक्षाओं का विशेषज्ञ नहीं हो सकते हैं और आपका enum घोंसला है, यह कक्षा के अंदर std::hash का उपयोग करने के लिए समस्याग्रस्त हो जाएगा। जैसा कि आपने इंगित किया है कि enums घोषित नहीं किया जा सकता है। इसलिए क्लास के अंदर विशेष 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 कक्षा A::Estd::hash के साथ-साथ अंदरूनी कक्षा के साथ भी A::Estd::hash के साथ उपयोग कर सकती है। साथ ही, यदि आप संदर्भ द्वारा std::unordered_set को एकत्रित नहीं करना चाहते हैं तो आप केवल आंतरिक उपयोग के लिए कस्टम हैशर लागू कर सकते हैं (और फिर std::hash इसे कॉल करें)।

1

ऐसा लगता है कि आपने पहले से ही अपने प्रश्न में सभी कोणों को कवर किया है।

मैं ऐसा करने का कोई तरीका नहीं सोच सकता।

सारांश यह है, आप केवल स्थिति के तथ्यों को बदल सकते हैं:

  • enum गैर नेस्टेड बनाने (एक संलग्न नाम स्थान में यह बजाय रखें) या
  • में के रूप में स्पष्ट रूप से क़मी बनाने की मशीन फ़ंक्शन का उपयोग करें आपका उदाहरण
3

एक संभावना है कि एनम को बेस क्लास में रखा जाए। दुर्भाग्यवश, आपको प्रत्येक enum सदस्य के लिए एक उपयोग घोषणा प्रदान करनी है। इसके चारों ओर एक तरफ एक स्कोप्ड एनम (enum class Bar) का उपयोग करना है, जिसके लिए Foo::SOME_VALUE के बजाय Foo::Bar::SOME_VALUE जैसे उपयोग की आवश्यकता है। ऐसा करने के लिए, आपको केवल using FooBase::Bar; की आवश्यकता होगी।

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

ओह यह आविष्कारशील है। मैं इसका इस्तेमाल नहीं करता, लेकिन मैंने चकित किया। :) –

संबंधित मुद्दे

 संबंधित मुद्दे