2013-01-23 13 views
11

मैं इन सबसे छुटकारा छोरों सी शैली ताररेंज अशक्त पर छोरों के लिए आधारित समाप्त तार

void print_C_str(const char* str) 
{ 
    for(char c : str) 
    { 
     cout << c; 
    } 
} 

का समर्थन करेगा के लिए आधारित है कि सीमा मान लिया हालांकि यह स्थिति नहीं है, मानक [stmt.ranged] (6.5.4) का कहना है कि सीमा के आधार पर-के लिए 3 संभावनाओं में से एक में काम करता है:

  1. रेंज एक सरणी
  2. रेंज एक प्रतिदेय begin और end विधि के साथ एक वर्ग है

जब मैं ग्लोबल नेम स्पेस में const char* के लिए begin और end कार्यों को जोड़ने मैं अभी भी (दोनों VS12 और जीसीसी 4.7 से) त्रुटियों मिल एक संबद्ध नाम स्थान (प्लस std नाम स्थान) में ADL से पहुंचा जा सकता है।

वहाँ एक रास्ता रेंज आधारित के लिए छोरों सी शैली तार के साथ काम करने के लिए है?

मैं namespace std के लिए एक अधिभार जोड़ने की कोशिश की और यह काम किया, लेकिन मेरी समझ में यह namespace std के भार के जोड़ने के लिए अवैध है (यह सही है?)

+2

आप कानूनी तौर पर एसटीडी नाम स्थान में टेम्पलेट्स विशेषज्ञ कर सकते हैं। – inf

+6

@ बांसबोन सच है लेकिन आईआईआरसी केवल उपयोगकर्ता परिभाषित प्रकारों के लिए है और यह एक अधिभार है और एक अंतर्निहित प्रकार के लिए नहीं, एक यूडीटी नहीं है। – Motti

+1

आप सी तारों के आसपास क्यों गुजर रहे हैं? –

उत्तर

19

यदि आप शून्य-समाप्त तारों के लिए एक छोटा इटेटरेटर लिखते हैं, तो आप पॉइंटर पर फ़ंक्शन को कॉल करने के बजाय पॉइंटर पर एक फ़ंक्शन को कॉल करके ऐसा कर सकते हैं।

template <typename Char> 
struct null_terminated_range_iterator { 
public: 
    // make an end iterator 
    null_terminated_range_iterator() : ptr(nullptr) {} 
    // make a non-end iterator (well, unless you pass nullptr ;) 
    null_terminated_range_iterator(Char* ptr) : ptr(ptr) {} 

    // blah blah trivial iterator stuff that delegates to the ptr 

    bool operator==(null_terminated_range_iterator const& that) const { 
     // iterators are equal if they point to the same location 
     return ptr == that.ptr 
      // or if they are both end iterators 
      || is_end() && that.is_end(); 
    } 

private: 
    bool is_end() { 
     // end iterators can be created by the default ctor 
     return !ptr 
      // or by advancing until a null character 
      || !*ptr; 
    } 

    Char* ptr; 
} 

template <typename Char> 
using null_terminated_range = boost::iterator_range<null_terminated_range_iterator<Char>>; 
// ... or any other class that aggregates two iterators 
// to provide them as begin() and end() 

// turn a pointer into a null-terminated range 
template <typename Char> 
null_terminated_range<Char> null_terminated_string(Char* str) { 
    return null_terminated_range<Char>(str, {}); 
} 

और उपयोग इस तरह दिखता है:

for(char c : null_terminated_string(str)) 
{ 
    cout << c; 
} 

मैं यह किसी भी अभिव्यक्ति खो देता है नहीं लगता। असल में, मुझे लगता है कि यह एक स्पष्ट है।

+4

+1 में हैं, यह * क्लीनर है क्योंकि यह सही ढंग से 'char *' और 'char []' दोनों के साथ काम करता है।'Char []' के साथ समस्या यह है कि यह मूल रूप से काम करता है लेकिन गलत चीज (इसे शून्य-समाप्त स्ट्रिंग की बजाय किसी भी सी-सर के रूप में माना जाता है, और इसके परिणामस्वरूप एक तत्व बहुत लंबा होता है। –

+0

+1 उत्सुकता से बाहर, क्या इस समाधान को 'char c: std :: string (str)) के लिए प्राथमिकता दी जाएगी? यह मेरे लिए एक स्पष्ट समाधान प्रतीत होता है। जैसा कि किसी ने इसे उत्तर के रूप में पोस्ट नहीं किया है, मैं केवल अनुमान लगा सकता हूं कि वहां है मुझे कुछ याद आ रहा है। इस समाधान में आपने पोस्ट किया है या 'std :: string' का उपयोग करके पुनरावृत्ति करने के लिए बनाई गई कुछ अतिरिक्त ज़रूरतें हैं। – hmjd

+2

@hmjd हां,' के लिए (char c: std :: string (str)) 'है वैकल्पिक। std :: स्ट्रिंग पर इस दृष्टिकोण का लाभ यह है कि इस अवशोषण में बहुत कम रनटाइम लागत है: निर्मित अतिरिक्त वस्तुएं बेहद सस्ते हैं, std :: स्ट्रिंग के विपरीत जो गतिशील आवंटन को शामिल कर सकती है और पूरे स्ट्रिंग को कॉपी कर देगी अपने स्वयं के बफर। मूल रूप से, जबकि मैं std :: स्ट्रिंग को देखने पर नहीं झुकाऊंगा इसके लिए उपयोग किया जाता है (जब तक प्रोफाइलिंग इसे एक प्रदर्शन मुद्दा साबित नहीं करता), यह वांछित कार्यक्षमता वांछित, पुनरावृत्ति प्रदान करता है, जबकि std :: string unneeded कार्यक्षमता प्रदान करता है और यही लागत है। –

2

एक सी-स्ट्रिंग एक सरणी नहीं है, यह एक वर्ग नहीं है कि begin/end सदस्य हैं, और आपको एडीएल द्वारा कुछ भी नहीं मिलेगा क्योंकि तर्क एक आदिम है। तर्कसंगत रूप से, यह एडीएल के साथ सादा अयोग्यतापूर्ण लुकअप होना चाहिए, जो वैश्विक नामस्थान में एक फ़ंक्शन पायेगा। लेकिन, शब्द दिया, मैं सोच रहा हूं कि यह संभव नहीं है।

2

एक संभावित समाधान, रैप करने के लिए अशक्त एक और प्रकार में स्ट्रिंग समाप्त है। निम्नतम कार्यान्वयन निम्नानुसार है (यह R. Martinho Fernandes के सुझाव से कम प्रदर्शन करता है क्योंकि यह strlen पर कॉल करता है लेकिन यह भी काफी कम कोड है)।

class null_terminated_range { 
    const char* p: 
public: 
    null_terminated_range(const char* p) : p(p) {} 
    const char * begin() const { return p; } 
    const char * end() const { return p + strlen(p); } 
}; 

उपयोग:

for(char c : null_terminated_range(str)) 
संबंधित मुद्दे