2010-05-27 10 views
7

मैं एक समारोह है जहां मैं एक कंटेनर जो तार (जैसे vector<string>, set<string>, list<string>) और, एक शुरुआत इटरेटर और एक अंत इटरेटर को देखते हुए, प्रसंस्करण इटरेटर रेंज के माध्यम से जाने धारण तार।स्वीकार stl_container_type <string> की टेम्प्लेटेड पैरामीटर :: iterator

वर्तमान में समारोह इस तरह घोषित किया जाता है:

template< typename ContainerIter> 
void ProcessStrings(ContainerIter begin, ContainerIter end); 

अब इस किसी भी प्रकार जो operator* को लागू करने की अंतर्निहित इंटरफेस के अनुरूप स्वीकार करेंगे, उपसर्ग operator++ और जो कुछ अन्य कॉल समारोह शरीर में हैं।

template< typename Container<string>::iterator> 
void ProcessStrings(Container<string>::iterator begin, Container<string>::iterator end); 

ताकि मैं इस तरह के रूप में इसका इस्तेमाल कर सकते हैं::

vector<string> str_vec; 
list<string> str_list; 
set<SomeOtherClass> so_set; 

ProcessStrings(str_vec.begin(), str_vec.end()); // OK 
ProcessStrings(str_list.begin(), str_list.end()); //OK 
ProcessStrings(so_set.begin(), so_set.end()); // Error 

क्या मैं सच में करना चाहते हैं एक जो नीचे स्पष्ट रूप से इनपुट की राशि को प्रतिबंधित करता है (स्यूडोकोड चेतावनी) की तरह एक परिभाषा है

अनिवार्य रूप से, मैं जो करने की कोशिश कर रहा हूं वह फ़ंक्शन विनिर्देश को प्रतिबंधित करता है ताकि यह उस कार्य के उपयोगकर्ता को स्पष्ट कर सके जो इसे स्वीकार करता है और यदि कोड संकलित करने में विफल रहता है तो उन्हें एक संदेश मिलता है कि वे गलत पैरामीटर प्रकारों का उपयोग कर रहे हैं फ़ंक्शन बॉडी में कुछ जो XXX Funct है आयन XXX वर्ग के लिए नहीं मिला।

+0

क्या आप इसे 'std :: string' या किसी भी' std :: basic_string' प्रकार पर प्रतिबंधित करना चाहते हैं? –

+0

आह, वास्तव में कोई _needs_ __concepts__! दुर्भाग्यवश, उन्हें सी ++ मानकीकरण समिति के एक प्रमुख सदस्य की सिफारिश पर पिछले गर्मियों में फेंक दिया गया था, क्योंकि उन्होंने सी ++ 0x के उस बिंदु पर आने में देरी की जहां 'एक्स' हेक्साडेसिमल अंक बन गया। – sbi

+0

आपको अपने टेम्पलेट को कॉल करने के लिए प्रतिबंधित क्यों करना है? टेम्पलेट का पूरा बिंदु अच्छी तरह से निर्मित एल्गोरिदम का पुन: उपयोग सक्षम है। – jmucchiello

उत्तर

4

आप एक टेम्पलेट टेम्पलेट पैरामीटर के साथ इस के पास प्राप्त कर सकते हैं:

template<template<class> class CONTAINER> 
void ProcessStrings(CONTAINER<string>&); 

यह एक पूरे कंटेनर पर कार्रवाई करेंगे, और एक संकलन त्रुटि दिखा सकते हैं अगर यह तार शामिल नहीं है।

ProcessStrings(str_vec); // OK 
ProcessStrings(so_set); // Error 

आप इटरेटर सीमाओं के साथ काम करने के लिए चाहते हैं, तो सबसे अच्छा मैं कर सकता प्रबंधक

template<template<class> class CONTAINER> 
void ProcessStrings(typename CONTAINER<string>::iterator, 
        typename CONTAINER<string>::iterator); 

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

ProcessStrings<vector>(str_vec.begin(), str_vec.end()); // OK 
ProcessStrings<set>(so_set.begin(), so_set.end()); // Error 

क्या कोई इस पर सुधार कर सकता है?

+1

मुझे आश्चर्य होगा कि यह 'टेम्पलेट कंटेनर' का उपयोग करके काम करता है क्योंकि आपको टेम्पलेट पैरामीटर की सटीक संख्या निर्दिष्ट करने की आवश्यकता है और न केवल कई आबादी हैं जिनके आधार पर हम किस कंटेनर के बारे में बात कर रहे हैं, लेकिन यह भी मुद्दा है कि एसटीएल कार्यान्वयन कुछ पूरक पैरामीटर जोड़ सकता है जब तक कि उनके पास उचित चूक हो ... –

+0

@Matthieu: मुझे यकीन है कि टेम्पलेट तर्क कटौती एक मैच खोजने के लिए डिफ़ॉल्ट तर्क भर सकती है। निश्चित रूप से, जब मैंने जीसीसी के साथ परीक्षण किया तो यह कोड काम करता था। –

2

आप boost::enable_if टेम्पलेट जादू का उपयोग करके ऐसे चेक लागू कर सकते हैं। नीचे दी गई विधि संकलित नहीं की जाएगी जब तक कि इटरेटर का मान प्रकार प्रकार स्ट्रिंग न हो।

template<class It> 
boost::enable_if_c< 
     boost::is_same< typename boost::iterator_value<It>::type, string >::value 
>::type 
ProcessStrings(It itBegin, It itEnd) 
{ } 

तो boost::iterator_value<It>::type प्रकार स्ट्रिंग की है, boost::enable_if<...>::type शून्य करने के लिए, अपनी वापसी पैरामीटर का मूल्यांकन करेंगे। अन्यथा, SFINAE (प्रतिस्थापन-विफलता एक त्रुटि नहीं है) सिद्धांत के कारण, विधि को बिना त्रुटि के संकलित नहीं किया जाएगा।

+1

फ़ंक्शन बॉडी के भीतर या तो 'enable_if' या' static_assert' काम करना चाहिए। 'शून्य 'रिटर्न प्रकार निकालें (यह इसे निर्दिष्ट करने के लिए' enable_if' की नौकरी है)। –

+0

@Maththieu धन्यवाद, आप सही हैं। शून्य वापसी मूल्य एक टाइपो था। – Sebastian

0

#include <string> 
#include <vector> 
#include <list> 

template<template<typename T,typename A> class C> 
void ProcessStrings(typename C<std::string, std::allocator<std::string> >::iterator begin, 
        typename C<std::string, std::allocator<std::string> >::iterator end) 
{ 
} 


int main() 
{ 
    std::vector<std::string> strVec; 
    std::list<std::string>  strList; 
    std::list<int>    intList; 

    ProcessStrings<std::vector>(strVec.begin(), strVec.end()); 
    ProcessStrings<std::list>(strList.begin(), strList.end()); 
    ProcessStrings<std::list>(intList.begin(), intList.end()); // This will fail 
} 
+0

क्या आप विस्तार कर सकते हैं कि यह जवाब माइक से अलग कैसे है? मुझे लगता है कि यह आवंटक पैरामीटर निर्दिष्ट करता है, लेकिन क्या यह वास्तव में एक महत्वपूर्ण अंतर है? –

+0

जब मैंने पोस्ट किया तो मुझे माइक्स नहीं दिखाई दिए। लेकिन मैंने अभी कोशिश की है और मैं इसे कंटेनर टेम्पलेट में सभी प्रकार के पैरामीटर को स्पष्ट रूप से निर्दिष्ट किए बिना काम करने के लिए प्रतीत नहीं कर सकता। मुझे नहीं पता कि यह मेरा कंपाइलर है या कुछ और मैंने समस्या को हल करने की कोशिश नहीं की है। –

1

एक सरल लेकिन प्रभावी तरीका आज़माएं।

template <class T> 
struct is_basic_string: boost::mpl::false_ {}; 

template <class CharT, class Traits, class Alloc> 
struct is_basic_string< std::basic_string<CharT, Traits, Alloc> >: 
    boost::mpl::true_ {}; 

और फिर मान प्रकार की जाँच करने के

void ProcessStrings(Iterator begin, Iterator end) 
{ 
    BOOST_MPL_ASSERT_MSG(
    is_basic_string< typename boost::value_type<Iterator>::type >, 
    ONLY_ACCEPT_ITERATOR_TO_BASIC_STRING, 
    (Iterator) 
); 

    // do your work 
} 

चेक संदर्भ here इसका इस्तेमाल, इस मैक्रो संकलन समय में संभव के रूप में सार्थक संदेशों प्रदान करती है।

यह Sebastian समाधान से थोड़ा अधिक सामान्य है ... लेकिन std::wstring अंतर्राष्ट्रीयकरण के लिए काफी आसान है और आप उस पर जोर नहीं देना चाहेंगे।

अब बहुत अच्छा सवाल है ... आप ऐसा क्यों करना चाहेंगे!

जेनेरिक प्रोग्रामिंग का बहुत ही लक्ष्य उन कार्यों का उत्पादन करना है जो किसी भी प्रकार के साथ काम कर सकते हैं जो आंतरिक रूप से उपयोग किए जाने वाले संचालन का अनुपालन करता है। आप जानबूझकर इसे प्रतिबंधित क्यों करना चाहते हैं?

+0

'basic_string' का उपयोग करने के बारे में अतिरिक्त विवरण के लिए धन्यवाद, प्रश्न के लिए एक दिलचस्प विस्तार। मैंने मूल प्रश्न पर @jmucchiello द्वारा एक टिप्पणी का जवाब दिया है कि मुझे उम्मीद है कि अंतिम अनुच्छेद में आपके प्रश्न के लिए कुछ प्रकार की स्पष्टीकरण प्रदान की जाएगी। –

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