লুপগুলির জন্য রেঞ্জ-ভিত্তিক ব্যবহারের সময় পুনরুক্তি প্রয়োজন


85

বর্তমানে, আমি এটির সাহায্যে কেবল বিস্তৃত লুপগুলিই করতে পারি:

for (auto& value : values)

তবে কখনও কখনও আমার কোনও রেফারেন্সের পরিবর্তে (যে কারণেই হোক না কেন) মানটির জন্য একটি পুনরুক্তি প্রয়োজন। পুরো ভেক্টরের সাথে মানগুলির তুলনা করেই কি কোনও পদ্ধতি আছে?

উত্তর:


78

পুরানো 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সর্বদা সিঙ্ক থাকে।


হ্যাঁ, আমি এটিই করছি। আমি কেবল ভাবছিলাম যে এর পরিবর্তে রেঞ্জ ভিত্তিক লুপগুলির সাথে কোনও সমাধান আছে
太郎

4
লুপের জন্য পুরানোদের সাথে প্রথম সমাধানটি আরও ভাল: আমি সম্মত হলাম: পি
太郎 太郎

@ 小 太郎: অথবা আপনি std::findযা প্রয়োজন তা যদি একটি মান সনাক্ত করা হয় তবে আপনি ব্যবহার করতে পারেন ... ভাল পুরানো অ্যালগরিদমগুলি এখনও নতুন স্ট্যান্ডার্ডে রয়েছে।
ডেভিড রদ্রিগেজ -

4
@ ডেভিড: যদি ভেক্টরে নকল থাকে? 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);
}

আহ, ভাল হ্যাঁ আমি এটি বলার মতো বেশিরভাগই পাইনি যে, সংকলকটি কনস্ট্রাক্টরের কাছ থেকে তার টি পেতে পারে ... তাই আমি ডিক্লাইপিংয়ের কথা ভেবেছিলাম এবং ব্যবহার-প্রসারণ দেখেছি ... এবং আমি দেখিনি যে এটি কোনও ফাংশন থেকে তার টি পেতে পারে ... ফাংশন টেম্পলেট, ধন্যবাদ। এটা ঠিক আছে, আমি এখন এটি কিভাবে?
পেডলোড

4
হ্যাঁ, ভাল লাগছে। FWIW করুন, boost::counting_iteratorযদিও যা ঠিক করে, এবং সুবিধামত সঙ্গে আবৃত করা হয়, boost::counting_range, তাই আপনি লিখতে পারেন: for(auto it : boost::counting_range(r.begin(), r.end()))। :)
Xeo

4
আমি মনে করি operator++()একটি ফিরিয়ে দেওয়া উচিত InnerIterator, অন্যথায় খুব সুন্দর এবং সুন্দর।
বেন ভয়েগট

2

জাভাতে forসি ++ কাউন্টার পার্ট হিসাবে পরিসীমা ভিত্তিক লুপ তৈরি করা হয়েছে যা foreachঅ্যারের উপাদানগুলির সহজ পুনরাবৃত্তিকে অনুমতি দেয়। এটি ইটারেটরগুলির মতো জটিল কাঠামোগুলির ব্যবহার অপসারণের জন্য যাতে এটি সহজ করে তোলে। আমি আপনাকে একটি চাই iterator, যেমন নওয়াজ বলেছিলেন, আপনাকে স্বাভাবিক forলুপ ব্যবহার করতে হবে ।


আমি আশা করি তারা একটি অনুরূপ লুপ অফার করবে ব্যবহৃত iterators পরিবর্তে, যদিও :(
小太郎

4
আমি খুশি যে আপনি যা পাচ্ছেন তা হ'ল তারা মূল্যবান এবং পুনরুক্তিকারী নয়, আমার জন্য পরিসীমা ভিত্তিক forসিনট্যাক্স চিনির এবং টাইপিংয়ের পরিমাণ হ্রাস করার বিষয়ে। auto
পুনরাবৃত্তিটি

2

এটি করার একটি খুব সহজ উপায় আছে std::vector, প্রক্রিয়া চলাকালীন আপনি যদি ভেক্টরকে পুনরায় আকার দিচ্ছেন তবে এটিও কাজ করা উচিত (গ্রহণযোগ্য উত্তর এই ক্ষেত্রে বিবেচনা করে কিনা তা আমি নিশ্চিত নই)

যদি bআপনার ভেক্টর হয় তবে আপনি ঠিক করতে পারেন

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

যেখানে iterআপনার প্রয়োজনীয় পুনরাবৃত্তি হবে।

এটি সি ++ ভেক্টর সর্বদা সংঘবদ্ধ হওয়ার সুযোগটি গ্রহণ করে ।


4
আপনি ইতিমধ্যে যে সি ++ ভেক্টর সংলগ্ন হয় শোষণ হয়, আপনি হিসাবে ভাল করেন যে কোন বিবেকী বাস্তবায়ন শুধু typedef হবে কাজে লাগান পারে vector<T>::iteratorথেকে T*চেক করে একটি সঙ্গে 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;
}

4
আমার কোন শব্দ নেই, এটি এতগুলি স্তরে ভুল, এটি সমালোচনা করা কোথায় শুরু করব তাও আমি জানতাম না।
সোয়াইনোন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.