2012-06-25 21 views
5

मैं कुछ कोड दोबारा कर रहा था और पाया कि एक ही कोड के साथ एक ही कोड के साथ लिखा जा सकता है, एक सेट के तुलनित्र को छोड़कर less<double> और दूसरे स्थान पर है। कुछ की तरह:std :: set रनटाइम पर कम या अधिक तुलनित्र का चयन करें

double MyClass::GeneralFunction(double val, bool condition) 
{ 
    if(condition) 
    { 
     // Select greater as comparator 
    } 
    else 
    { 
     // Select less as comparator 
    } 

    set<double, comparator> s; 
    // common code 
} 

मैं, यह मेरी कस्टम तुलनित्र कार्यों का उपयोग करके काम कर दिया है इस तरह::

double MyClass::Function1(double val) 
{ 
    std::set<double, less<double> > s; 
    // Do something with s 
} 

double MyClass::Function2(double val) 
{ 
    std::set<double, greater<double> > s; 
    // Do the same thing with s as in Function1 
} 

तो मैं क्या कर के बारे में सोचा

bool my_greater(double lhs, double rhs) 
{ 
    return lhs > rhs; 
} 

bool my_less(double lhs, double rhs) 
{ 
    return lhs < rhs; 
} 

double MyClass::GeneralFunction(double val, bool condition) 
{ 
    typedef bool(*Comparator) (double, double); 
    Comparator comp = &my_less; 
    if (condition) 
    { 
     comp = &my_greater; 
    } 

    std::set<double, Comparator > s(comp); 

    //.... 
} 

लेकिन मैं चाहते हैं अंतर्निहित लोगों का उपयोग करने के लिए। समस्या यह है कि मुझे नहीं पता कि तुलनित्र को कैसे घोषित किया जाए और इसे भविष्य में निर्मित किया जाए।

किसी भी मदद की सराहना की जाएगी।

उत्तर

4

तुम सच में एक क्रम की जांच की जरूरत है?

template <class Comp> double MyClass::Function(double val) 
{ 
    std::set<double, Comp > s; 
    // Do something with s 
} 

यहां तक ​​कि अगर आप ऐसा करेंगे, तो आप अभी भी

double MyClass::Function(double val, bool comp) 
{ 
    return comp ? Function<std::less<double> >(val) : Function<std::greater<double> >(val); 
} 
+0

धन्यवाद! मुझे वास्तव में रनटाइम चेक की आवश्यकता नहीं थी, इसलिए मैं कॉलर में तुलनित्र का चयन कर सकता था। 'Std :: function' के उपयोग के लिए – MikMik

2

क्यों औपचारिक पैरामीटर द्वारा

template <typename Compare> 
double MyClass::GeneralFunction(double val) 
{ 
    std::set<double, Compare> s; 

    //.... 
} 

खाका चयन नहीं कर कुछ सी ++ बहुत अच्छी तरह से हैंडल नहीं है। कॉलर को टेम्पलेट तर्क की आपूर्ति करके संकलन चरण में जितना संभव हो उतना पुश करें।

तो फिर तुम, एक आवरण प्रदान कर सकते हैं यदि आप वास्तव में कार्यावधि में से एक का चयन करना चाहते हैं:

double MyClass::GeneralFunction(double val, bool condition) 
{ 
    return condition ? 
     GeneralFunction<std::greater<double> >(val) : 
     GeneralFunction<std::less <double> >(val);\ 
} 
3

उपयोग कर सकते हैं बस अपने सेट के रूप में

std::set<double, std::function<bool(double,double)>> 

का उपयोग, और इतना है कि यह दृष्टांत:

typedef std::set<double, std::function<bool(double,double)> > RTSet; 

RTSet choose_ordering(bool increasing) 
{ 
    if (increasing) 
     return RTSet(std::less<double>()); 
    else 
     return RTSet(std::greater<double>()); 
} 

हर तुलना पर
  • जांच के आदेश, या
  • यह एक बार इन्स्टेन्शियशन पर जाँच लेकिन फिर भी हर कार्य कॉल पर एक अविवेक (के लिए एक आभासी समारोह कॉल की तरह उठाना: सामान्य अपनी दुविधा मेंनोट या तो करने के लिए है उदाहरण)

मैं दूसरा विकल्प पसंद कर रहा हूं ताकि आप सेट में उपयोग करते समय ऑर्डरिंग को गलती से बदल नहीं सकें, इसके सभी आविष्कारों को तोड़ दें।


बस एक त्वरित सोचा, इस के रूप में संभावित रूप से एक अलग जवाब (और यहां तक ​​कि प्रश्न) हो सकता है, लेकिन आप का उल्लेख कोड के दो टुकड़े सॉर्ट क्रम को छोड़ कर एक कर रहे हैं।

तो आप कर सकते हैं एक वैकल्पिक मैं कुछ स्थितियों में उपयोग किया है,, एक भी तरह दिशा का उपयोग करें और कोड सेट पर ऑपरेटिंग (इटरेटर प्रकार के अनुसार) टेम्पलेट है

if (increasing) 
    do_stuff(set.begin(), set.end()); 
else 
    do_stuff(set.rbegin(), set.rend()); 
+0

+1। सेट का उपयोग होने पर गलती से ऑर्डरिंग को बदलने के जोखिम के संबंध में: कोई ध्वज एक कार्यात्मक वस्तु का एक निजी सदस्य होना चाहिए, जो जोखिम को बहुत कम कर देता है। –

+0

std :: फ़ंक्शन भाग वह था जो मैं वास्तव में पूछ रहा था, लेकिन एमएसल्टर्स का जवाब एक बेहतर समाधान था, मुझे लगता है। – MikMik

4

समस्या यह है कि आप ट्यूनटाइम पर तुलनित्र के std::less और std::greater पर असंबंधित प्रकारों का चयन नहीं कर सकते हैं। इसी प्रकार, std::less के साथ तुलनित्र के साथ तत्काल std::greater के साथ तत्काल पर एक प्रकार से संबंधित नहीं है। वहाँ कई संभव समाधान हैं, लेकिन सबसे सरल (और केवल एक inhertance, आभासी कार्यों और गतिशील आवंटन को शामिल नहीं ) साथ तुम क्या कर रहे की तर्ज है:

class SelectableCompare 
{ 
    bool myIsGreater; 
public: 
    SelectableCompare(bool isGreater) : myIsGreater(isGreater) {} 
    bool operator()(double d1, double d2) const 
    { 
     static std::less<double> const less; 
     return myIsGreater 
      ? less(d2, d1) 
      : less(d1, d2); 
    } 
}; 

मैं मानक का उपयोग किया है std::less और std::greater क्योंकि आप ऐसा करने में रुचि व्यक्त करते हैं। double के मामले में, यह स्पष्ट रूप से, अधिक है; मैं आमतौर पर बस d1 > d2 और d1 < d2 लिखूंगा। उपर्युक्त का टेम्पलेट संस्करण, हालांकि, कुछ समझ सकता है, क्योंकि प्रकारों में एक विशेष std::less हो सकता है। यही कारण है कि मैं केवल std::less का उपयोग करता हूं; यह काफी कल्पना की जा सकती है कि एक प्रोग्रामर केवल std::less विशेषज्ञ है, यह ज्ञान के साथ कि यह केवल मानक लाइब्रेरी में ऑर्डर करने के लिए उपयोग किया जाता है।

बस पूरा होने के लिए:

class Comparator 
{ 
public: 
    virtual ~Comparator() {} 
    virtual bool isLessThan(double d1, double d2) const = 0; 
}; 

, विभिन्न तुलना के लिए नहीं बल्कि स्पष्ट व्युत्पन्न वर्ग, और एक: स्पष्ट विकल्प एक सार तुलनित्र आधार के साथ, तुलनित्र में रणनीति पैटर्न का उपयोग करने के लिए है आवरण स्मृति प्रबंधन करने के लिए:

class ComparatorWrapper 
{ 
    std::shared_ptr<Comparator> myComparator; 
public: 
    ComparatorWrapper(Comparator* newed_comparator) 
     : myComparator(newed_comparator) 
    { 
    } 
    bool operator()(double d1, double d2) const 
    { 
     return myComparator->isLessThan(d1, d2); 
    } 
}; 

यह निश्चित रूप से द्विआधारी विकल्प आप की जरूरत के लिए overkill है, लेकिन अगर वहाँ और अधिक विकल्प थे उपयुक्त हो सकता है; जैसे set जो हो सकता है कई अलग-अलग क्षेत्रों में से एक (विभिन्न प्रकार के सभी प्रकार) में से एक पर क्रमबद्ध।