छोरों के लिए रंग-आधारित का उपयोग करते समय पुनरावृत्ति की आवश्यकता होती है


84

वर्तमान में, मैं केवल इस पर आधारित लूप्स कर सकता हूं:

for (auto& value : values)

लेकिन कभी-कभी मुझे संदर्भ के बजाय (जो भी कारण के लिए) मूल्य के लिए एक पुनरावृत्ति की आवश्यकता होती है। क्या पूरे वेक्टर तुलना मूल्यों के माध्यम से जाने के लिए कोई विधि नहीं है?

जवाबों:


77

पुराने forलूप का उपयोग करें :

for (auto it = values.begin(); it != values.end();  ++it )
{
       auto & value = *it;
       //...
}

इसके साथ valueही आप इट्रेटर भी हैं it। आप जो भी उपयोग करना चाहते हैं, उसका उपयोग करें।


संपादित करें:

हालाँकि, मैंने इसकी सिफारिश नहीं की है, लेकिन यदि आप रेंज-आधारित forलूप (हाँ, जो भी कारण : डी) का उपयोग करना चाहते हैं, तो आप यह कर सकते हैं:

 auto it = std::begin(values); //std::begin is a free function in C++11
 for (auto& value : values)
 {
     //Use value or it - whatever you need!
     //...
     ++it; //at the end OR make sure you do this in each iteration
 }

यह दृष्टिकोण दिए गए खोज को टालता है value, क्योंकि valueऔर itहमेशा सिंक में रहता है।


हाँ, यह वही है जो मैं कर रहा हूं। मैं सोच रहा था कि क्या इसके बजाय हल आधारित छोरों के साथ एक समाधान था
Wondering

4
मैं मानता हूं कि लूप के लिए पुराने के साथ पहला समाधान बहुत बेहतर है: पी
太郎 '

@ @ Need: या आप उपयोग कर सकते हैं std::findयदि आपको किसी मूल्य का पता लगाने की आवश्यकता है ... अच्छे पुराने एल्गोरिदम अभी भी नए मानक में हैं।
डेविड रॉड्रिग्ज - dribeas

1
@ डेविड: अगर वेक्टर में डुप्लिकेट हैं तो क्या होगा? valueऔर itसिंक में नहीं हो सकता है। याद valueएक संदर्भ है।
नवाज

9
@ नवाज: मुझे लगता है कि मैंने आखिरी वाक्य को गलत समझा। मुझे लगा कि वह किसी ज्ञात वस्तु का पता लगाने के लिए रेंज का उपयोग कर रहा है। BTW, जब भी संभव हो (अपने कोड में दोनों का उपयोग करता है) को प्राथमिकता ++itदें it++क्योंकि यह कम ओवरहेड हो सकता है।
डेविड रोड्रिगेज -

15

यहाँ एक प्रॉक्सी रैपर क्लास है जो आपको छिपे हुए इटरेटर को अपने स्वयं के वैरिएबल में अलियासिंग करने की अनुमति देता है।

#include <memory>
#include <iterator>

/*  Only provides the bare minimum to support range-based for loops.
    Since the internal iterator of a range-based for is inaccessible,
    there is no point in more functionality here. */
template< typename iter >
struct range_iterator_reference_wrapper
    : std::reference_wrapper< iter > {
    iter &operator++() { return ++ this->get(); }
    decltype( * std::declval< iter >() ) operator*() { return * this->get(); }
    range_iterator_reference_wrapper( iter &in )
        : std::reference_wrapper< iter >( in ) {}
    friend bool operator!= ( range_iterator_reference_wrapper const &l,
                             range_iterator_reference_wrapper const &r )
        { return l.get() != r.get(); }
};

namespace unpolluted {
    /*  Cannot call unqualified free functions begin() and end() from 
        within a class with members begin() and end() without this hack. */
    template< typename u >
    auto b( u &c ) -> decltype( begin( c ) ) { return begin( c ); }
    template< typename u >
    auto e( u &c ) -> decltype( end( c ) ) { return end( c ); }
}

template< typename iter >
struct range_proxy {
    range_proxy( iter &in_first, iter in_last )
        : first( in_first ), last( in_last ) {}

    template< typename T >
    range_proxy( iter &out_first, T &in_container )
        : first( out_first ),
        last( unpolluted::e( in_container ) ) {
        out_first = unpolluted::b( in_container );
    }

    range_iterator_reference_wrapper< iter > begin() const
        { return first; }
    range_iterator_reference_wrapper< iter > end()
        { return last; }

    iter &first;
    iter last;
};

template< typename iter >
range_proxy< iter > visible_range( iter &in_first, iter in_last )
    { return range_proxy< iter >( in_first, in_last ); }

template< typename iter, typename container >
range_proxy< iter > visible_range( iter &first, container &in_container )
    { return range_proxy< iter >( first, in_container ); }

उपयोग:

#include <vector>
#include <iostream>
std::vector< int > values{ 1, 3, 9 };

int main() {
    // Either provide one iterator to see it through the whole container...
    std::vector< int >::iterator i;
    for ( auto &value : visible_range( i, values ) )
        std::cout << "# " << i - values.begin() << " = " << ++ value << '\n';

    // ... or two iterators to see the first incremented up to the second.
    auto j = values.begin(), end = values.end();
    for ( auto &value : visible_range( j, end ) )
        std::cout << "# " << j - values.begin() << " = " << ++ value << '\n';
}

13

मैंने खुद इस पर कोशिश की और एक समाधान पाया।

उपयोग:

for(auto i : ForIterator(some_list)) {
    // i is the iterator, which was returned by some_list.begin()
    // might be useful for whatever reason
}

कार्यान्वयन उतना मुश्किल नहीं था:

template <typename T> struct Iterator {
    T& list;
    typedef decltype(list.begin()) I;

    struct InnerIterator {
        I i;
        InnerIterator(I i) : i(i) {}
        I operator * () { return i; }
        I operator ++ () { return ++i; }
        bool operator != (const InnerIterator& o) { return i != o.i; }
    };

    Iterator(T& list) : list(list) {}
    InnerIterator begin() { return InnerIterator(list.begin()); }
    InnerIterator end() { return InnerIterator(list.end()); }
};
template <typename T> Iterator<T> ForIterator(T& list) {
    return Iterator<T>(list);
}

आह, हाँ ठीक है। मुझे यह कहने के लिए काफी नहीं मिला, कि कंपाइलर कंस्ट्रक्टर से अपना टी प्राप्त कर सकता है ... इसलिए मैंने डिक्लेप्ट के बारे में सोचा और उपयोग-ब्लोट को देखा ... और मैंने नहीं देखा कि यह एक फ़ंक्शन से अपना टी प्राप्त कर सकता है। ... समारोह टेम्पलेट, धन्यवाद। क्या यह सही है, अब मैं इसे कैसे करूं?
पेलोड

2
हाँ, यह अच्छा लग रहा है। एफडब्ल्यूआईडब्ल्यू, boost::counting_iteratorहालांकि, जो वास्तव में ऐसा करता है, और आसानी से लपेटा जाता है boost::counting_range, इसलिए आप लिख सकते हैं for(auto it : boost::counting_range(r.begin(), r.end())):। :)
XIO

1
मुझे लगता है कि operator++()एक वापसी करनी चाहिए InnerIterator, अन्यथा बहुत अच्छी और uesful
बेन Voigt

2

रेंज आधारित for लूप foreachजावा में सी ++ समकक्ष के रूप में बनाया गया है जो सरणी तत्वों के आसान पुनरावृत्ति की अनुमति देता है। इसका अर्थ पुनरावृत्तियों जैसी जटिल संरचनाओं के उपयोग को हटाने के लिए है ताकि इसे सरल बनाया जा सके। मैं आपको एक चाहता हूं iterator, जैसा कि नवाज ने कहा, आपको सामान्य forलूप का उपयोग करना होगा ।


काश वे एक समान पाश की पेशकश करेगा कि इस्तेमाल किया iterators बजाय, हालांकि :(
小太郎

1
मुझे खुशी है कि आपको जो कुछ भी मिल रहा है, वह मूल्य है और इट्रेटर नहीं है, मेरे लिए सीमा आधारित forचीनी है और टाइपिंग राशि को कम करने के बारे में है। विशेष रूप से उपयोग किए जाने पर auto
पुनरावृत्ति करने वाले को पुनरावृत्ति करने में कठिनाई

2

इसके लिए ऐसा करने का एक बहुत ही सरल तरीका है std::vector, जो इस प्रक्रिया के दौरान वेक्टर का आकार बदलने पर भी काम करना चाहिए (मुझे यकीन नहीं है कि स्वीकृत उत्तर इस मामले पर विचार करता है)

यदि bआपका वेक्टर है, तो आप बस कर सकते हैं

for(auto &i:b){
    auto iter = b.begin() + (&i-&*(b.begin()));
}

iterआपका आवश्यक पुनरावृत्ति कहां होगा।

यह इस तथ्य का लाभ उठाता है कि C ++ वैक्टर हमेशा सन्निहित हैं


2
यदि आप पहले से ही इस तथ्य का फायदा उठा रहे हैं कि C ++ वैक्टर सन्निहित हैं, तो आप इस तथ्य का भी फायदा उठा सकते हैं कि कोई भी सेंस कार्यान्वयन केवल टाइप vector<T>::iteratorकरने के लिए होगा T*: यह देखें कि a के साथ static_assert(), तो बस उपयोग करें T* iter = &i;
सेंटास्टर -

1

चलो इसे बहुत गंदा करते हैं ... मुझे पता है, 0x70h स्टैक-उपयोग, संकलक संस्करण के साथ बदल रहा है, .... इसे संकलक द्वारा उजागर किया जाना चाहिए, लेकिन यह नहीं है :-(

char* uRBP = 0; __asm { mov uRBP, rbp }
Iterator** __pBegin = (Iterator**)(uRBP+0x70);
for (auto& oEntry : *this) {
    if (oEntry == *pVal) return (*__pBegin)->iPos;
}

1
मेरे पास कोई शब्द नहीं है, यह इतने सारे स्तरों में गलत है, मुझे यह भी नहीं पता होगा कि इसे कहाँ से शुरू करना है।
सूनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.