2010-12-04 27 views
15

के तत्वों के किसी भी कंटेनर पर एक एसटीएल इटरेटर लेता है, मैं किसी भी प्रकार के एसटीएल कंटेनर पर एक इटरेटर इनपुट के रूप में एक फ़ंक्शन को कैसे परिभाषित करता हूं, लेकिन केवल एक विशिष्ट टेम्पलेट प्रकार के उन लोगों के लिए। उदाहरण के लिए:फ़ंक्शन जो एक विशिष्ट प्रकार

प्रपत्र का कोई भी इटरेटर std::list<Unit*>::iteratorयाstd::vector<Unit*>::iterator

मैं सिर्फ समारोह std::list<Unit*>::iterator लेने के लिए परिभाषित करेगा, लेकिन अगर हम एक अलग एसटीएल कंटेनर के लिए स्विच, मैं बदलना होगा नहीं करना चाहते मेरा कोड

क्या टेम्पलेट्स के साथ ऐसा करने का कोई तरीका है या अन्यथा?

+2

'std :: list'? एसटीएल कंटेनरों में कच्चे पॉइंटर्स? गाह! :) –

उत्तर

14

आप का निर्माण boost::enable_if जैसे कर सकते हैं जो सत्यापित करता है कि नेस्टेड टाइपपीफ iterator::value_type वास्तव में उचित प्रकार का है या नहीं।

template<class T, class Iterator> 
typename boost::enable_if<boost::is_same<typename Iterator::value_type, T> >::type 
    f(Iterator i) 
{ 
    /* ... */ 
} 

int main() 
{ 
    std::list<int> l; 
    std::vector<int> v; 

    f<int>(l.begin()); // OK 
    f<int>(v.begin()); // OK 

    std::vector<float> v2; 
    f<int>(v2.begin()); /* Illegal */ 
} 

यह है कि मैं क्या से समझ "एक समारोह है कि इनपुट के रूप में एसटीएल कंटेनर के किसी भी प्रकार के ऊपर एक इटरेटर लेता है, लेकिन केवल एक विशिष्ट टेम्प्लेट प्रकार के उन लोगों के लिए" है, लेकिन मेरी व्याख्या गलत हो सकता है।

+0

यह मेरे लिए एक बहुत ही उपयोगी उत्तर था। धन्यवाद! –

6

आप केवल my_special_type के कंटेनर पर फिर से शुरू करना चाहते हैं? उस मामले में:

template <bool, typename T> 
struct enable_if; 

template <typename T> 
struct enable_if<true, T> 
{ 
    typedef T type; 
}; 

template <typename T, typename U> 
struct is_same 
{ 
    enum {value = false}; 
}; 

template <typename T> 
struct is_same<T, T> 
{ 
    enum {value = true}; 
}; 

template <typename Iter> 
typename enable_if<is_same<typename Iter::value_type, your_special_type>::value, 
        void>::type 
function(Iter begin, Iter end) 
{ 
    // ... 
} 
+0

दिलचस्प! हालांकि, अगर गलत प्रकार के साथ फ़ंक्शन का उपयोग किया जाता है तो यहां क्या होता है? क्षमा करें अगर यह मामूली है। मैं अभी भी टेम्पलेट सीख रहा हूँ। – RyanG

+0

@Ryan: 'enable_if' में केवल 'टाइप' सदस्य है यदि पहला टेम्पलेट पैरामीटर' सत्य' है। यदि आप गलत का उपयोग करते हैं तो आप संकलन में असफल हो जाएंगे। – Bill

+0

@Ryan: समारोह नहीं * 'enable_if' :) – fredoverflow

5

एक और तरीका है टेम्पलेट के साथ करता है, तो शर्त पूरी नहीं कर रहा है एक स्थिर दावे को गति प्रदान करने के लिए है।

#include <iterator> 
#include <boost/type_traits/is_same.hpp>  
#include <boost/static_assert.hpp> 

template <class Type, class Iter> 
void foo(Iter from, Iter to) 
{ 
    BOOST_STATIC_ASSERT((boost::is_same<typename std::iterator_traits<Iter>::value_type, Type>::value)); 
    //... 
} 

int main() 
{ 
    int arr[10]; 
    foo<int>(arr, arr + 10); //OK 
    foo<double>(arr, arr + 10); //triggers static assertion 
} 

आप टेम्पलेट्स को खत्म करना चाहते हैं, तो यह भी संभव प्रकार विलोपन का उपयोग कर एक "any_iterator" लिखने के लिए है। उदाहरण के लिए, की तरह इस पर:

template <typename Iter> 
void function(Iter first, Iter last){ 
    Unit* val = *first; 
} 

यह: http://stlab.adobe.com/classadobe_1_1any__iterator.html

14

SFINAE पर निर्भर मौजूदा जवाब के अलावा, एक सरल सन्निकटन बस इटरेटर के रूप में एक मनमाना टेम्पलेट प्रकार लेने के लिए समारोह को परिभाषित करने के होगा कुछ डाउनसाइड्स हैं। SFINAE समाधान (जैसे boost::enable_if) के विपरीत, यह आपको बिल्कुल नहीं देता है जो आपने पूछा था। यह तब तक संकलित होता है जब तक Iter की ऑब्जेक्ट को परिवर्तनीय Unit* पर कनवर्ट करने के लिए संदर्भित किया जा सकता है, जो काफी समान नहीं है। आपको कोई गारंटी नहीं है कि Iter एक पूरी तरह से एसटीएल-अनुरूप इटरेटर है (यह सिर्फ एक और प्रकार हो सकता है जो operator* को परिभाषित करता है), या इसका मान प्रकार Unit* ठीक है।

दूसरी ओर, यह बहुत आसान है।

0

खैर मैं मामले में एक सरल typedef है कि आप केवल समय में एक कंटेनर प्रकार की जरूरत है (अगर मैं अपने USECASE सही ढंग से यह मामला है समझ में आ)

template <class T> 
class ContainerIterator 
{ 
    Container(); 
    public: 
    typedef std::list<T>::iterator type; 
} 

//usage: 
void function(ContainerIterator<YourType>::type begin, ContainerIterator<YourType>::type end) 
{ 
    //... 
} 

बाद में कंटेनर स्विच करने के लिए प्रयोग करेंगे , टाइपिफ़ में कंटेनर प्रकार को बस बदलें।

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