কীভাবে একটি এসটিএল-স্টাইলের পুনরাবৃত্তি কার্যকর করতে হবে এবং সাধারণ সমস্যাগুলি এড়ানো যায়?


305

আমি একটি সংগ্রহ তৈরি করেছি যার জন্য আমি একটি এসটিএল স্টাইল, র্যান্ডম-অ্যাক্সেস পুনরুক্তি সরবরাহ করতে চাই। আমি একটি পুনরাবৃত্তির উদাহরণ প্রয়োগের জন্য চারপাশে অনুসন্ধান করছিলাম কিন্তু আমি কোনও পাইনি। আমি কনস্ট্যান্ট ওভারলোডগুলি []এবং *অপারেটরগুলির প্রয়োজনীয়তা সম্পর্কে জানি । "এসটিএল-স্টাইল" হওয়ার জন্য একজন পুনরুক্তি করার প্রয়োজনীয়তাগুলি কী কী এবং (যদি থাকে) এড়াতে অন্য কোনও সমস্যাগুলি কী কী?

অতিরিক্ত প্রসঙ্গ: এটি একটি লাইব্রেরির জন্য এবং আমি সত্যিকারের প্রয়োজন না হলে আমি এর উপর কোনও নির্ভরতা প্রবর্তন করতে চাই না। আমি একই সংকলক সহ সি ++ 03 এবং সি ++ 11 এর মধ্যে বাইনারি সামঞ্জস্যতা সরবরাহ করতে সক্ষম হতে আমার নিজের সংগ্রহটি লিখি (সুতরাং কোনও এসটিএল যা সম্ভবত ভেঙে যাবে)।


13
+1 টি! দুর্দান্ত প্রশ্ন। আমি একই জিনিস ভাবছি। বুস্ট.আইট্রেটারের ভিত্তিতে কিছু মিলিয়ে ঝাঁকুনি দেওয়া যথেষ্ট সহজ, তবে আপনি যদি স্ক্র্যাচ থেকে এটি প্রয়োগ করেন তবে প্রয়োজনীয়তার একটি তালিকা খুঁজে পাওয়া অবাক করা কঠিন।
জাল্ফ

2
আপনার পুনরুক্তিকারীদের SCARY হতে হবে তাও মনে রাখবেন। boost.org/doc/libs/1_55_0/doc/html/intrusive/…
alfC

উত্তর:


232

http://www.cplusplus.com/references/std/iterator/ এর একটি সহজ চার্ট রয়েছে যা C ++ 11 স্ট্যান্ডার্ডের .2 24.2.2 এর চশমা বর্ণনা করে। মূলত, পুনরাবৃত্তির কাছে এমন ট্যাগ রয়েছে যা বৈধ ক্রিয়াকলাপগুলি বর্ণনা করে এবং ট্যাগগুলির একটি শ্রেণিবিন্যাস থাকে। নীচে নিখুঁতভাবে প্রতীকী, এই শ্রেণিগুলি বাস্তবে এরূপ অস্তিত্ব নেই।

iterator {
    iterator(const iterator&);
    ~iterator();
    iterator& operator=(const iterator&);
    iterator& operator++(); //prefix increment
    reference operator*() const;
    friend void swap(iterator& lhs, iterator& rhs); //C++11 I think
};

input_iterator : public virtual iterator {
    iterator operator++(int); //postfix increment
    value_type operator*() const;
    pointer operator->() const;
    friend bool operator==(const iterator&, const iterator&);
    friend bool operator!=(const iterator&, const iterator&); 
};
//once an input iterator has been dereferenced, it is 
//undefined to dereference one before that.

output_iterator : public virtual iterator {
    reference operator*() const;
    iterator operator++(int); //postfix increment
};
//dereferences may only be on the left side of an assignment
//once an output iterator has been dereferenced, it is 
//undefined to dereference one before that.

forward_iterator : input_iterator, output_iterator {
    forward_iterator();
};
//multiple passes allowed

bidirectional_iterator : forward_iterator {
    iterator& operator--(); //prefix decrement
    iterator operator--(int); //postfix decrement
};

random_access_iterator : bidirectional_iterator {
    friend bool operator<(const iterator&, const iterator&);
    friend bool operator>(const iterator&, const iterator&);
    friend bool operator<=(const iterator&, const iterator&);
    friend bool operator>=(const iterator&, const iterator&);

    iterator& operator+=(size_type);
    friend iterator operator+(const iterator&, size_type);
    friend iterator operator+(size_type, const iterator&);
    iterator& operator-=(size_type);  
    friend iterator operator-(const iterator&, size_type);
    friend difference_type operator-(iterator, iterator);

    reference operator[](size_type) const;
};

contiguous_iterator : random_access_iterator { //C++17
}; //elements are stored contiguously in memory.

আপনি হয় বিশেষজ্ঞ করতে পারেন std::iterator_traits<youriterator>, বা একই টাইপিডেফগুলি নিজেই পুনরুক্তিতে স্থাপন করতে পারেন বা উত্তরাধিকারী হতে পারেন std::iterator(যার মধ্যে এই টাইপডেফ রয়েছে)। stdনেমস্পেসে জিনিস পরিবর্তন করা এবং পঠনযোগ্যতার জন্য আমি দ্বিতীয় বিকল্পটি পছন্দ করি , তবে বেশিরভাগ লোক এখান থেকে উত্তরাধিকার সূত্রে আসে std::iterator

struct std::iterator_traits<youriterator> {        
    typedef ???? difference_type; //almost always ptrdiff_t
    typedef ???? value_type; //almost always T
    typedef ???? reference; //almost always T& or const T&
    typedef ???? pointer; //almost always T* or const T*
    typedef ???? iterator_category;  //usually std::forward_iterator_tag or similar
};

উল্লেখ্য iterator_category কোনো একটি হওয়া আবশ্যক std::input_iterator_tag, std::output_iterator_tag, std::forward_iterator_tag, std::bidirectional_iterator_tag, অথবা std::random_access_iterator_tag, যা প্রযোজনীয়তা আপনার পুনরুক্তিকারীর সন্তুষ্ট উপর নির্ভর করে। আপনার পুনরুক্তিকারী উপর নির্ভর করে, আপনি বিশেষজ্ঞ চয়ন করতে পারেন std::next,std::prev , std::advance, এবং std::distanceসেইসাথে, কিন্তু এই খুব কমই প্রয়োজন হয়। ইন অত্যন্ত বিরল ক্ষেত্রে আপনি বিশেষজ্ঞ করতে চাইতে পারেন std::beginএবং std::end

আপনার ধারকটির সম্ভবত একটিও থাকা উচিত const_iterator ধারকটিতে সম্ভবত একটিও , যা ধ্রুবক ডেটার জন্য একটি (সম্ভবত পরিবর্তনযোগ্য) পুনরাবৃত্তকারী যা আপনার মতো একই রকম হয় iteratorতবে এটি কোনও থেকে স্পষ্টতই গঠনযোগ্য iteratorহওয়া উচিত এবং ব্যবহারকারীরা ডেটা পরিবর্তন করতে অক্ষম হবে। এর অভ্যন্তরীণ পয়েন্টারটি অ-ধ্রুবক ডেটার জন্য পয়েন্টার হওয়া সাধারণ, এবং কোডের নকলকে হ্রাস করতে তাই iteratorউত্তরাধিকার সূত্রে প্রাপ্ত const_iterator

আপনার নিজের এসটিএল কনটেইনার লেখার সময়ে আমার পোস্টে আরও একটি সম্পূর্ণ ধারক / পুনরাবৃত্তি প্রোটোটাইপ রয়েছে।


2
std::iterator_traitsটাইপডেফগুলি std::iteratorনিজেরাই বিশেষায়িত বা সংজ্ঞায়িত করার পাশাপাশি, আপনি কেবলমাত্র এর থেকে পাওয়া যেতে পারেন , যা এর জন্য এটির টেমপ্লেটের পরামিতিগুলির উপর নির্ভর করে আপনার জন্য সংজ্ঞা দেয়।
খ্রিস্টান রাউ

3
@ লোকিআস্তারি: সম্পূর্ণ ডকুমেন্টেশন বেশ বিস্তৃত (খসড়ায় 40 টি পৃষ্ঠাগুলি), এবং স্ট্যাক ওভারফ্লোয়ের সুযোগে নয়। যাইহোক, আমি পুনরাবৃত্তকারী ট্যাগ এবং আরও বিশদ সম্পর্কিত আরও তথ্য যুক্ত করেছি const_iterator। আমার পোস্টের আর কী অভাব ছিল? আপনি ক্লাসে যুক্ত করার মতো আরও কিছু বোঝাচ্ছেন, তবে প্রশ্নটি বিশেষভাবে পুনরাবৃত্তিকারীদের বাস্তবায়ন সম্পর্কে।
মাকিং হাঁস

5
std::iteratorসি ++ 17 এ অবমূল্যায়নের প্রস্তাব দেওয়া হয়েছিল ; এটি ছিল না, তবে আমি এটির বেশি সময় ধরে এটি ঘুরে দেখব না।
einpoklum

2
@ আইনপোকলমের মন্তব্যে একটি আপডেট: সর্বোপরি হ্রাস std::iteratorকরা হয়েছে।
scry

1
@ জোনাথনলি: বাহ, এটি operator boolঅবিশ্বাস্যরকম বিপজ্জনক। কেউ একটি ব্যাপ্তির শেষ সনাক্ত করতে এটি ব্যবহার করার চেষ্টা করবে while(it++), তবে পুনরাবৃত্তিটি কোনও প্যারামিটার দিয়ে তৈরি করা হয়েছিল কিনা তা সত্যই যাচাই করে নেওয়া হয়।
হাঁসকে

16

iterator_facade ডকুমেন্টেশন Boost.Iterator থেকে আমরা কী একটি লিঙ্ক তালিকার জন্য iterators বাস্তবায়নের উপর একটা চমৎকার টিউটোরিয়াল দেখে মনে হচ্ছে প্রদান করে। আপনি আপনার ধারক উপর একটি এলোমেলো অ্যাক্সেস পুনরুক্তি নির্মাণের জন্য এটি একটি সূচনা পয়েন্ট হিসাবে ব্যবহার করতে পারেন?

আর কিছু না হলে, আপনি প্রদত্ত সদস্য ফাংশন এবং টাইপডেফগুলি একবার দেখে নিতে পারেন iterator_facadeএবং এটি আপনার নিজের তৈরির জন্য একটি সূচনা পয়েন্ট হিসাবে ব্যবহার করতে পারেন।



10

এখানে কাঁচা পয়েন্টার পুনরাবৃত্তির নমুনা।

কাঁচা পয়েন্টার নিয়ে কাজ করার জন্য আপনার পুনরাবৃত্ত শ্রেণীর ব্যবহার করা উচিত নয়!

#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <assert.h>

template<typename T>
class ptr_iterator
    : public std::iterator<std::forward_iterator_tag, T>
{
    typedef ptr_iterator<T>  iterator;
    pointer pos_;
public:
    ptr_iterator() : pos_(nullptr) {}
    ptr_iterator(T* v) : pos_(v) {}
    ~ptr_iterator() {}

    iterator  operator++(int) /* postfix */         { return pos_++; }
    iterator& operator++()    /* prefix */          { ++pos_; return *this; }
    reference operator* () const                    { return *pos_; }
    pointer   operator->() const                    { return pos_; }
    iterator  operator+ (difference_type v)   const { return pos_ + v; }
    bool      operator==(const iterator& rhs) const { return pos_ == rhs.pos_; }
    bool      operator!=(const iterator& rhs) const { return pos_ != rhs.pos_; }
};

template<typename T>
ptr_iterator<T> begin(T *val) { return ptr_iterator<T>(val); }


template<typename T, typename Tsize>
ptr_iterator<T> end(T *val, Tsize size) { return ptr_iterator<T>(val) + size; }

কাঁচা পয়েন্টার পরিসীমা ভিত্তিক লুপ workaround। দয়া করে, আমাকে সংশোধন করুন, যদি কাঁচা পয়েন্টার থেকে ব্যাপ্তি ভিত্তিক লুপ তৈরি করার আরও ভাল উপায় থাকে।

template<typename T>
class ptr_range
{
    T* begin_;
    T* end_;
public:
    ptr_range(T* ptr, size_t length) : begin_(ptr), end_(ptr + length) { assert(begin_ <= end_); }
    T* begin() const { return begin_; }
    T* end() const { return end_; }
};

template<typename T>
ptr_range<T> range(T* ptr, size_t length) { return ptr_range<T>(ptr, length); }

এবং সহজ পরীক্ষা

void DoIteratorTest()
{
    const static size_t size = 10;
    uint8_t *data = new uint8_t[size];
    {
        // Only for iterator test
        uint8_t n = '0';
        auto first = begin(data);
        auto last = end(data, size);
        for (auto it = first; it != last; ++it)
        {
            *it = n++;
        }

        // It's prefer to use the following way:
        for (const auto& n : range(data, size))
        {
            std::cout << " char: " << static_cast<char>(n) << std::endl;
        }
    }
    {
        // Only for iterator test
        ptr_iterator<uint8_t> first(data);
        ptr_iterator<uint8_t> last(first + size);
        std::vector<uint8_t> v1(first, last);

        // It's prefer to use the following way:
        std::vector<uint8_t> v2(data, data + size);
    }
    {
        std::list<std::vector<uint8_t>> queue_;
        queue_.emplace_back(begin(data), end(data, size));
        queue_.emplace_back(data, data + size);
    }
}

5

সবার আগে আপনি এখানে বিভিন্ন ক্রিয়াকলাপের স্বতন্ত্র পুনরাবৃত্তকারীগুলির বিভিন্ন ধরনের সমর্থন করতে চান তার তালিকা দেখতে পারেন ।

এরপরে, আপনি যখন আপনার পুনরাবৃত্ত শ্রেণীর তৈরি করেছেন তখন আপনাকে std::iterator_traitsএটির জন্য বিশেষীকরণ করতে হবে এবং প্রয়োজনীয় কিছু typedef(যেমন iterator_categoryবা value_type) সরবরাহ করতে হবে বা বিকল্পভাবে এগুলি সংগ্রহ করতে হবে std::iterator, যা typedefআপনার জন্য প্রয়োজনীয় সংজ্ঞা দেয় এবং তাই ডিফল্টর সাথে ব্যবহার করা যেতে পারেstd::iterator_traits

দাবি অস্বীকার: আমি জানি কিছু লোকেরা cplusplus.comএগুলি পছন্দ করেন না তবে তারা কিছু সত্যিকারের দরকারী তথ্য সরবরাহ করে।


আমি সত্যিই সিপ্লেসপ্লাস বনাম সিপ্রেফারেন্স বিতর্ক পাই না, এগুলি উভয়ই ভাল এবং অনেকগুলি জিনিস অনুপস্থিত। তবে সি ++ একমাত্র ভাষা যেখানে স্ট্যান্ডার্ড লাইব্রেরি পুনরাবৃত্তি বাস্তবায়ন হ'ল নরক এক্সডি। বেশিরভাগ সময় একটি স্ট্রিল কন্টেইনারে একটি রিটার ক্লাস লেখার জন্য একটি আয়রেটর এক্সডি বাস্তবায়নের চেয়ে সহজ
কোফডি ডেভেলপার

@ গেইম ডেভেলপার এই টেম্পলেট লাইব্রেরিটি পরীক্ষা করুন যা আমি পুনরাবৃত্তিকারীদের প্রয়োগের জন্য লিখেছি: github.com/VinGarcia/Simple-Iterator-Template । এটি খুব সহজ এবং একটি পুনরুক্তি লেখার জন্য কোডের প্রায় 10 লাইনের প্রয়োজন।
ভিনগারিয়া

চমৎকার ক্লাস, আমি এটির প্রশংসা করি, এটি নন-এসটিএল পাত্রে (EA_STL, UE4) দিয়েও সংকলন করার জন্য এটি সম্ভবত পোর্টিংয়ের উপযুক্ত .. এটি বিবেচনা করুন! :)
কফডি ডেভেলপার

যাইহোক, যদি একমাত্র কারণ হ'ল সিপিপ্লসপ্লাস.কম কিছু সত্যিকারের দরকারী তথ্য সরবরাহ করে, cppreferences.com আরও বেশি দরকারী তথ্য সরবরাহ করে ...
এলএফ

@ এলএফ তারপর নির্দ্বিধায় সময় মতো ফিরে যান এবং সেই তথ্যটি সাইটের 2011 এর সংস্করণে যুক্ত করুন। ;-)
খ্রিস্টান রাউ

3

আমি বিভিন্ন কারণে (আংশিক শিক্ষাগত, আংশিক সীমাবদ্ধতা) হিসাবে আপনার মতো একই নৌকায় ছিলাম / ছিলাম। আমাকে স্ট্যান্ডার্ড লাইব্রেরির সমস্ত পাত্রে আবার লিখতে হয়েছিল এবং পাত্রে স্ট্যান্ডার্ডের সাথে মানিয়ে নিতে হয়েছিল। এর অর্থ, যদি আমি আমার স্টেটারের সাথে আমার ধারকটি সরিয়ে নিয়ে যাই সংস্করণটি তবে কোডটি একই কাজ করবে। যার অর্থ হ'ল আমাকে পুনরাবৃত্তিকারীদের পুনরায় লিখতে হয়েছিল।

যাইহোক, আমি EASTL এর দিকে তাকালাম । কনটেইনার সম্পর্কে একটি টন শিখানো ছাড়াও আমি স্টাইলের পাত্রে ব্যবহার করে বা আমার স্নাতক কোর্সের মাধ্যমে এই সময়টি কখনও শিখিনি । মূল কারণ হ'ল ইএএসটিএল স্টলারের চেয়ে বেশি পঠনযোগ্য কাউন্টার (আমি এটি কেবলমাত্র সমস্ত ম্যাক্রো এবং স্ট্রেট ফরোয়ার্ড কোডিং স্টাইলের অভাবের কারণেই পেয়েছি)। সেখানে কিছু অদ্ভুত জিনিস রয়েছে (যেমন ব্যাতিক্রমের জন্য # আইফডিফস) তবে আপনাকে অভিভূত করার মতো কিছুই নেই।

অন্যরা যেমন উল্লেখ করেছে, পুনরাবৃত্তকারী এবং পাত্রে cplusplus.com এর রেফারেন্সটি দেখুন।


3

আমি বেশ কয়েকটি বিভিন্ন পাঠ্য অ্যারেগুলিতে পুনরাবৃত্তি করতে সক্ষম হওয়ার সমস্যাটি সমাধান করার চেষ্টা করছিলাম যা সমস্তই একটি মেমরি বাসিন্দার ডাটাবেসের মধ্যে সংরক্ষণ করা হয় যা একটি বিশাল struct

নিম্নলিখিতটি একটি এমএফসি পরীক্ষা অ্যাপ্লিকেশনটিতে ভিজ্যুয়াল স্টুডিও 2017 সম্প্রদায় সংস্করণ ব্যবহার করে কাজ করা হয়েছিল। আমি এটি উদাহরণ হিসাবে অন্তর্ভুক্ত করছি কারণ এই পোস্টিংটি এমন বেশ কয়েকটিগুলির মধ্যে একটি যা আমি দৌড়ে গিয়েছিলাম যে এখনও কিছু সহায়তা সরবরাহ করা হয়েছে যা এখনও আমার প্রয়োজনের জন্য অপর্যাপ্ত ছিল।

structধারণকারী মেমরির বাসিন্দা ডেটাকে নিম্নলিখিত ভালো কিছু লাগছিল। আমি বংশবৃদ্ধির জন্য বেশিরভাগ উপাদানগুলি সরিয়ে দিয়েছি এবং ব্যবহৃত প্রিপ্রসেসর সংজ্ঞায়িতগুলিও অন্তর্ভুক্ত করি নি (ব্যবহৃত এসডিকে সি এর পাশাপাশি সি ++ এবং পুরানো)।

আমি যা করতে আগ্রহী তা হল বিভিন্ন WCHARদ্বিমাত্রিক অ্যারেগুলির জন্য আইট্রেটারগুলি রাখা যা স্মৃতিবিদ্যার জন্য পাঠ্য স্ট্রিং রয়েছে।

typedef struct  tagUNINTRAM {
    // stuff deleted ...
    WCHAR   ParaTransMnemo[MAX_TRANSM_NO][PARA_TRANSMNEMO_LEN]; /* prog #20 */
    WCHAR   ParaLeadThru[MAX_LEAD_NO][PARA_LEADTHRU_LEN];   /* prog #21 */
    WCHAR   ParaReportName[MAX_REPO_NO][PARA_REPORTNAME_LEN];   /* prog #22 */
    WCHAR   ParaSpeMnemo[MAX_SPEM_NO][PARA_SPEMNEMO_LEN];   /* prog #23 */
    WCHAR   ParaPCIF[MAX_PCIF_SIZE];            /* prog #39 */
    WCHAR   ParaAdjMnemo[MAX_ADJM_NO][PARA_ADJMNEMO_LEN];   /* prog #46 */
    WCHAR   ParaPrtModi[MAX_PRTMODI_NO][PARA_PRTMODI_LEN];  /* prog #47 */
    WCHAR   ParaMajorDEPT[MAX_MDEPT_NO][PARA_MAJORDEPT_LEN];    /* prog #48 */
    //  ... stuff deleted
} UNINIRAM;

বর্তমান পদ্ধতি হ'ল প্রতিটি অ্যারের জন্য প্রক্সি শ্রেণি সংজ্ঞায়িত করার জন্য একটি টেম্পলেট ব্যবহার করা এবং তারপরে একটি একক পুনরাবৃত্ত শ্রেণীর ব্যবস্থা করা যা অ্যারের প্রতিনিধিত্বকারী প্রক্সি অবজেক্টটি ব্যবহার করে একটি নির্দিষ্ট অ্যারেতে পুনরাবৃত্তি করতে ব্যবহৃত হতে পারে।

মেমোরি রেসিডেন্সিয়াল ডেটার একটি অনুলিপি কোনও বস্তুতে সংরক্ষণ করা হয় যা মেমোরির বাসিন্দার ডেটা / থেকে ডিস্কে পড়তে ও লিখতে পরিচালনা করে। এই শ্রেণিতে, CFileParaটেম্প্লেটেড প্রক্সি ক্লাস ( MnemonicIteratorDimSizeএবং উপ শ্রেণিটি এটি থেকে উদ্ভূত হয় MnemonicIteratorDimSizeBase) এবং পুনরুক্তি শ্রেণি MnemonicIterator,।

তৈরি প্রক্সি অবজেক্টটি একটি পুনরাবৃত্তকারী অবজেক্টের সাথে সংযুক্ত থাকে যা একটি বেস শ্রেণীর মাধ্যমে বর্ণিত ইন্টারফেসের মাধ্যমে প্রয়োজনীয় তথ্য অ্যাক্সেস করে যা থেকে সমস্ত প্রক্সি ক্লাস নেওয়া হয়। ফলাফলটি একক ধরণের পুনরাবৃত্ত শ্রেণীর হয় যা বিভিন্ন প্রক্সি ক্লাসের সাথে ব্যবহার করা যেতে পারে কারণ বিভিন্ন প্রক্সি ক্লাসগুলি সমস্ত একই ইন্টারফেস, প্রক্সি বেস শ্রেণির ইন্টারফেস প্রকাশ করে।

প্রথমটি ছিল শনাক্তকারীদের একটি সেট তৈরি করা যা কোনও শ্রেণীর কারখানায় সেই ধরণের স্মৃতিবিজ্ঞানের জন্য নির্দিষ্ট প্রক্সি অবজেক্ট তৈরি করার জন্য সরবরাহ করা হবে। এই সনাক্তকারীদের ব্যবহারকারীর ইন্টারফেসের অংশ হিসাবে ব্যবহার করা হয় ব্যবহারকারী নির্দিষ্ট প্রভিশন ডেটা সনাক্ত করতে এবং সম্ভবত পরিবর্তন করতে আগ্রহী।

const static DWORD_PTR dwId_TransactionMnemonic = 1;
const static DWORD_PTR dwId_ReportMnemonic = 2;
const static DWORD_PTR dwId_SpecialMnemonic = 3;
const static DWORD_PTR dwId_LeadThroughMnemonic = 4;

প্রক্সি ক্লাস

টেম্প্লেটেড প্রক্সি ক্লাস এবং এর বেস ক্লাসটি নিম্নরূপ। আমার বিভিন্ন ধরণের wchar_tপাঠ্য স্ট্রিং অ্যারে সমন্বিত করা দরকার। দ্বিমাত্রিক অ্যারে মিমোনমিকের ধরণ (উদ্দেশ্য) এবং বিভিন্ন ধরণের স্মৃতিবিজ্ঞানের বিভিন্ন ধরণের বিভিন্ন স্তরের স্তরের স্তরের পাঁচটি পাঠ্য অক্ষর এবং বিশটি পাঠ্য অক্ষরের মধ্যে পৃথক পৃথক পৃথক সংখ্যা ছিল। উত্সযুক্ত প্রক্সি শ্রেণীর জন্য টেমপ্লেটগুলি প্রতিটি স্মৃতিবিদ্যায় সর্বাধিক সংখ্যক অক্ষরের প্রয়োজন টেমপ্লেট সহ একটি প্রাকৃতিক ফিট ছিল। প্রক্সি অবজেক্টটি তৈরি হওয়ার পরে, আমরা তারপরে SetRange()প্রকৃত স্তন্যপায়ী অ্যারে এবং এর ব্যাপ্তি নির্দিষ্ট করতে পদ্ধতিটি ব্যবহার করি ।

// proxy object which represents a particular subsection of the
// memory resident database each of which is an array of wchar_t
// text arrays though the number of array elements may vary.
class MnemonicIteratorDimSizeBase
{
    DWORD_PTR  m_Type;

public:
    MnemonicIteratorDimSizeBase(DWORD_PTR x) { }
    virtual ~MnemonicIteratorDimSizeBase() { }

    virtual wchar_t *begin() = 0;
    virtual wchar_t *end() = 0;
    virtual wchar_t *get(int i) = 0;
    virtual int ItemSize() = 0;
    virtual int ItemCount() = 0;

    virtual DWORD_PTR ItemType() { return m_Type; }
};

template <size_t sDimSize>
class MnemonicIteratorDimSize : public MnemonicIteratorDimSizeBase
{
    wchar_t    (*m_begin)[sDimSize];
    wchar_t    (*m_end)[sDimSize];

public:
    MnemonicIteratorDimSize(DWORD_PTR x) : MnemonicIteratorDimSizeBase(x), m_begin(0), m_end(0) { }
    virtual ~MnemonicIteratorDimSize() { }

    virtual wchar_t *begin() { return m_begin[0]; }
    virtual wchar_t *end() { return m_end[0]; }
    virtual wchar_t *get(int i) { return m_begin[i]; }

    virtual int ItemSize() { return sDimSize; }
    virtual int ItemCount() { return m_end - m_begin; }

    void SetRange(wchar_t (*begin)[sDimSize], wchar_t (*end)[sDimSize]) {
        m_begin = begin; m_end = end;
    }

};

ইটারেটর ক্লাস

পুনরাবৃত্ত শ্রেণি নিজেই নিম্নলিখিত। এই শ্রেণিটি কেবলমাত্র মৌলিক ফরোয়ার্ড পুনরুক্তি কার্যকারিতা সরবরাহ করে যা এই মুহুর্তে প্রয়োজনীয়। তবে আমি প্রত্যাশা করি যে আমার এটির থেকে অতিরিক্ত কিছু প্রয়োজন হলে এটি পরিবর্তিত হবে বা বাড়ানো হবে।

class MnemonicIterator
{
private:
    MnemonicIteratorDimSizeBase   *m_p;  // we do not own this pointer. we just use it to access current item.
    int      m_index;                    // zero based index of item.
    wchar_t  *m_item;                    // value to be returned.

public:
    MnemonicIterator(MnemonicIteratorDimSizeBase *p) : m_p(p) { }
    ~MnemonicIterator() { }

    // a ranged for needs begin() and end() to determine the range.
    // the range is up to but not including what end() returns.
    MnemonicIterator & begin() { m_item = m_p->get(m_index = 0); return *this; }                 // begining of range of values for ranged for. first item
    MnemonicIterator & end() { m_item = m_p->get(m_index = m_p->ItemCount()); return *this; }    // end of range of values for ranged for. item after last item.
    MnemonicIterator & operator ++ () { m_item = m_p->get(++m_index); return *this; }            // prefix increment, ++p
    MnemonicIterator & operator ++ (int i) { m_item = m_p->get(m_index++); return *this; }       // postfix increment, p++
    bool operator != (MnemonicIterator &p) { return **this != *p; }                              // minimum logical operator is not equal to
    wchar_t * operator *() const { return m_item; }                                              // dereference iterator to get what is pointed to
};

প্রক্সি অবজেক্ট ফ্যাক্টরি নির্ধারণ করে যে কোন বস্তুটি স্মৃতিচায়ক সনাক্তকারীর উপর ভিত্তি করে তৈরি করা হবে। প্রক্সি অবজেক্টটি তৈরি করা হয়েছে এবং পয়েন্টারটি প্রত্যাশিত হ'ল স্ট্যান্ডার্ড বেস ক্লাসের ধরণ যাতে বিভিন্ন স্তন্যপায়ী বিভাগের মধ্যে কোনটি অ্যাক্সেস করা হচ্ছে তা নির্বিশেষে অভিন্ন ইন্টারফেস থাকে। SetRange()পদ্ধতি প্রক্সি বস্তু নির্দিষ্ট অ্যারে উপাদানের প্রক্সি প্রতিনিধিত্ব করে এবং অ্যারে উপাদানের পরিসর উল্লেখ করতে ব্যবহৃত হয়।

CFilePara::MnemonicIteratorDimSizeBase * CFilePara::MakeIterator(DWORD_PTR x)
{
    CFilePara::MnemonicIteratorDimSizeBase  *mi = nullptr;

    switch (x) {
    case dwId_TransactionMnemonic:
        {
            CFilePara::MnemonicIteratorDimSize<PARA_TRANSMNEMO_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_TRANSMNEMO_LEN>(x);
            mk->SetRange(&m_Para.ParaTransMnemo[0], &m_Para.ParaTransMnemo[MAX_TRANSM_NO]);
            mi = mk;
        }
        break;
    case dwId_ReportMnemonic:
        {
            CFilePara::MnemonicIteratorDimSize<PARA_REPORTNAME_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_REPORTNAME_LEN>(x);
            mk->SetRange(&m_Para.ParaReportName[0], &m_Para.ParaReportName[MAX_REPO_NO]);
            mi = mk;
        }
        break;
    case dwId_SpecialMnemonic:
        {
            CFilePara::MnemonicIteratorDimSize<PARA_SPEMNEMO_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_SPEMNEMO_LEN>(x);
            mk->SetRange(&m_Para.ParaSpeMnemo[0], &m_Para.ParaSpeMnemo[MAX_SPEM_NO]);
            mi = mk;
        }
        break;
    case dwId_LeadThroughMnemonic:
        {
            CFilePara::MnemonicIteratorDimSize<PARA_LEADTHRU_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_LEADTHRU_LEN>(x);
            mk->SetRange(&m_Para.ParaLeadThru[0], &m_Para.ParaLeadThru[MAX_LEAD_NO]);
            mi = mk;
        }
        break;
    }

    return mi;
}

প্রক্সি ক্লাস এবং Iterator ব্যবহার করে

প্রক্সি ক্লাস এবং তার পুনরুক্তিকরণগুলি স্মৃতিবিদ্যার CListCtrlতালিকা সহ কোনও বস্তু পূরণ করতে নিম্নলিখিত লুপে প্রদর্শিত হিসাবে ব্যবহৃত হয় । আমি তাই ব্যবহার করছি std::unique_ptrযাতে প্রক্সি ক্লাস যখন আমার আর প্রয়োজন হয় না এবং std::unique_ptrসুযোগের বাইরে চলে যায়, তখন স্মৃতিটি পরিষ্কার হয়ে যায়।

এই উত্স কোডটি যা করে তা হ'ল অ্যারের মধ্যে একটি প্রক্সি অবজেক্ট তৈরি করা structযা নির্দিষ্ট স্তন্যপায়ী শনাক্তকরণের সাথে সম্পর্কিত। এটি তখন সেই অবজেক্টের জন্য একটি ইেটরেটর তৈরি করে, নিয়ন্ত্রণ forপূরণের জন্য একটি ব্যাপ্তি ব্যবহার করে CListCtrlএবং পরে পরিষ্কার করে। এগুলি সমস্ত কাঁচা wchar_tপাঠ্য স্ট্রিং যা অ্যারে উপাদানগুলির সংখ্যা হুবহু তাই আমরা স্ট্রিংটি অস্থায়ী বাফারে অনুলিপি করতে পারি যাতে পাঠ্য শূন্য হয়ে যায়।

    std::unique_ptr<CFilePara::MnemonicIteratorDimSizeBase> pObj(pFile->MakeIterator(m_IteratorType));
    CFilePara::MnemonicIterator pIter(pObj.get());  // provide the raw pointer to the iterator who doesn't own it.

    int i = 0;    // CListCtrl index for zero based position to insert mnemonic.
    for (auto x : pIter)
    {
        WCHAR szText[32] = { 0 };     // Temporary buffer.

        wcsncpy_s(szText, 32, x, pObj->ItemSize());
        m_mnemonicList.InsertItem(i, szText);  i++;
    }

1

এবং এখন লুপের জন্য পরিসীমা-ভিত্তিক একটি কী পুনরাবৃত্তকারী।

template<typename C>
class keys_it
{
    typename C::const_iterator it_;
public:
    using key_type        = typename C::key_type;
    using pointer         = typename C::key_type*;
    using difference_type = std::ptrdiff_t;

    keys_it(const typename C::const_iterator & it) : it_(it) {}

    keys_it         operator++(int               ) /* postfix */ { return it_++         ; }
    keys_it&        operator++(                  ) /*  prefix */ { ++it_; return *this  ; }
    const key_type& operator* (                  ) const         { return it_->first    ; }
    const key_type& operator->(                  ) const         { return it_->first    ; }
    keys_it         operator+ (difference_type v ) const         { return it_ + v       ; }
    bool            operator==(const keys_it& rhs) const         { return it_ == rhs.it_; }
    bool            operator!=(const keys_it& rhs) const         { return it_ != rhs.it_; }
};

template<typename C>
class keys_impl
{
    const C & c;
public:
    keys_impl(const C & container) : c(container) {}
    const keys_it<C> begin() const { return keys_it<C>(std::begin(c)); }
    const keys_it<C> end  () const { return keys_it<C>(std::end  (c)); }
};

template<typename C>
keys_impl<C> keys(const C & container) { return keys_impl<C>(container); }

ব্যবহার:

std::map<std::string,int> my_map;
// fill my_map
for (const std::string & k : keys(my_map))
{
    // do things
}

এটাই আমি খুঁজছিলাম তবে কারও কাছে এটি ছিল না বলে মনে হয়।

আপনি আমার ওসিডি কোড প্রান্তিককরণটি বোনাস হিসাবে পান।

অনুশীলন হিসাবে, আপনার নিজের লিখুন values(my_map)

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