"লুপগুলির জন্য পরিসীমা-ভিত্তিক" দিয়ে কাজ করার জন্য কীভাবে আমার কাস্টম টাইপ করবেন?


252

অনেক লোকের মতো আজকাল আমি সি ++ 11 এ নিয়ে আসা বিভিন্ন বৈশিষ্ট্যগুলি চেষ্টা করে যাচ্ছি। আমার পছন্দের একটি হ'ল লুপগুলির জন্য পরিসর-ভিত্তিক "।

আমি বুঝতে পারি যে:

for(Type& v : a) { ... }

এর সমতুল্য:

for(auto iv = begin(a); iv != end(a); ++iv)
{
  Type& v = *iv;
  ...
}

এবং এটি begin()কেবল a.begin()স্ট্যান্ডার্ড পাত্রে ফিরবে ।

তবে আমি যদি আমার কাস্টম টাইপটি "লুপের জন্য রেঞ্জ-ভিত্তিক" করতে চাইছি -ওয়্যার ?

আমার কি শুধু বিশেষজ্ঞ করা উচিত begin()এবং end()?

যদি আমার কাস্টম প্রকারটি নেমস্পেসের সাথে সম্পর্কিত xml, আমি কি সংজ্ঞায়িত করব xml::begin()বা করব std::begin()?

সংক্ষেপে, এটি করার জন্য গাইডলাইনগুলি কী?


কোনও সদস্য begin/endবা বন্ধুকে স্থির বা নিখরচায় করেই এটি সম্ভব begin/end। : শুধু সতর্কতা অবলম্বন করা আবশ্যক, যা নামস্থানে আপনি বিনামূল্যে ফাংশন করা stackoverflow.com/questions/28242073/...
alfC

যে কেউ একটি ভাসা মান পরিসীমা যা একটি ধারক নয় উদাহরণ দিয়ে উত্তর পোস্ট করুন যায়নি: for( auto x : range<float>(0,TWO_PI, 0.1F) ) { ... }। আমি আগ্রহী যে আপনি কীভাবে এই বিষয়টির চারপাশে কাজ করেন যে `rator rator rator rator rator rator rator rator rator rator def def def def def def def def def def def def def def এবং *__beginএই ক্ষেত্রে dereferecing ( ) সম্পর্কে কী ? আমি মনে করি যদি কেউ আমাদেরকে দেখিয়েছেন কিভাবে এটি একটি মহান অবদান হবে যে সম্পন্ন করা হয়!
বিটিক্লার

উত্তর:


183

প্রশ্নটি (এবং সর্বাধিক উত্তর) এই ত্রুটি প্রতিবেদনের রেজোলিউশনে পোস্ট করার পরে থেকে মান পরিবর্তন করা হয়েছে ।

for(:)আপনার ধরণের একটি লুপ কাজ করার Xউপায় এখন দুটি উপায়ের একটি:

  • সদস্য তৈরি করুন X::begin()এবং X::end()এটি এমন কিছু ফেরত দেয় যা পুনরুক্তির মতো কাজ করে

  • একটি নিখরচায় ফাংশন তৈরি করুন begin(X&)এবং end(X&)এটি এমন কিছু প্রত্যাবর্তন করবে যা আপনার টাইপের মতো একই নেমস্পেসে Xপুনরুদ্ধারের মতো কাজ করে ¹

এবং constপ্রকরণের জন্য অনুরূপ । এটি ত্রুটি প্রতিবেদন পরিবর্তনগুলি প্রয়োগ করে এমন সংকলক এবং যেগুলি না করে তাদের উভয়ই কাজ করবে।

প্রত্যাবর্তিত বস্তুগুলিকে আসলে পুনরাবৃত্তকারী হতে হবে না। for(:)লুপ, C ++ স্ট্যান্ডার্ডের অধিকাংশ অংশের অসদৃশ, তাই কিছু সমতুল্য করতে প্রসারিত করতে নিদিষ্ট :

for( range_declaration : range_expression )

হয়ে:

{
  auto && __range = range_expression ;
  for (auto __begin = begin_expr,
            __end = end_expr;
            __begin != __end; ++__begin) {
    range_declaration = *__begin;
    loop_statement
  }
}

যেখানে ভেরিয়েবলগুলি শুরু হয় কেবল __তা প্রকাশের জন্য হয় এবং begin_exprএবং end_exprযাদু বলে begin/ end.² বলে ²

প্রারম্ভিক / শেষে ফেরতের মূল্যের প্রয়োজনীয়তাগুলি সহজ: আপনার অবশ্যই প্রি-ওভারলোড ++করতে হবে, প্রারম্ভিককরণের এক্সপ্রেশনগুলি বৈধ, বাইনারি !=যা বুলিয়ান প্রসঙ্গে ব্যবহার করা যেতে পারে তা নিশ্চিত করতে হবে, অ্যানারি *যা আপনাকে নির্দিষ্ট করে দিতে পারে এমন কিছু ফেরত দেয় range_declarationএবং জনসাধারণকে প্রকাশ করতে পারে বিনাশকারী।

কোনও পুনরুক্তির সাথে সামঞ্জস্যপূর্ণ না এমন উপায়ে করা সম্ভবত একটি খারাপ ধারণা, কারণ সি ++ এর ভবিষ্যতের পুনরাবৃত্তিগুলি যদি আপনার কোডটি ভাঙার ক্ষেত্রে তুলনামূলকভাবে অশ্বারোহী হতে পারে।

একদিকে যেমন, এটি সম্ভবত যুক্তিযুক্ত যে ভবিষ্যতে স্ট্যান্ডার্ডের পুনর্বিবেচনার end_exprচেয়ে ভিন্ন ধরণের প্রত্যাবর্তনের অনুমতি দেওয়া হবে begin_expr। এটি দরকারী যেটিতে এটি "অলস-শেষ" মূল্যায়নের (নাল-সমাপ্তি সনাক্তকরণের মতো) অনুমতি দেয় যা হাতের লিখিত সি লুপের মতো দক্ষ হওয়ার জন্য অনুকূলতা তৈরি করা এবং অন্যান্য অনুরূপ অন্যান্য সুবিধার জন্য সহজ।


¹ নোট করুন যে for(:)লুপগুলি কোনও auto&&ভেরিয়েবলের মধ্যে কোনও অস্থায়ী সঞ্চয় করে এবং এটি আপনাকে মূল্য হিসাবে চিহ্নিত করে। আপনি কোনও অস্থায়ী (বা অন্য মূল্য) দ্বারা পুনরাবৃত্তি করছেন কিনা তা সনাক্ত করতে পারবেন না; যেমন একটি ওভারলোড একটি দ্বারা কল করা হবে নাfor(:) লুপ । N4527 থেকে [stmt.ranged] 1.2-1.3 দেখুন।

Ither হয় begin/ endপদ্ধতিটি কল করুন , বা সিডি -স্টাইল অ্যারে সমর্থনের জন্য এডিএল-কেবলমাত্র ফাংশন begin/ এর লকিং / end, বা যাদু করুন। নোটটি কল করা std::beginহয় না যদি না range_expressionটাইপ করা বস্তুটি namespace stdএকই রকম বা নির্ভর করে returns


ভিতরে পরিসীমা জন্য অভিব্যক্তি আপডেট করা হয়েছে

{
  auto && __range = range_expression ;
  auto __begin = begin_expr;
  auto __end = end_expr;
  for (;__begin != __end; ++__begin) {
    range_declaration = *__begin;
    loop_statement
  }
}

ধরণের __beginএবং __enddecoupled হয়েছে।

এটি শেষ পুনরাবৃত্তিকে আরম্ভের মতো একই ধরণের না হওয়ার অনুমতি দেয়। আপনার শেষ পুনরাবৃত্তকারী টাইপটি "সেন্ডিনেল" হতে পারে যা কেবল !=আর্টিনেটর টাইপের সাথে সমর্থন করে।

কেন এই দরকারী একটি ব্যবহারিক উদাহরণ আপনার শেষ পুনরুক্তিকারীর পড়া "আপনার পরীক্ষা করতে পারবেন হয় char*দেখতে হলে পয়েন্ট '0'যখন" ==একটি সঙ্গে char*। এটি নাল-টার্মিনেটেড char*বাফারের মাধ্যমে পুনরাবৃত্তি করার সময় একটি সি ++ রেঞ্জের জন্য অভিব্যক্তিটি সর্বোত্তম কোড তৈরি করতে দেয় ।

struct null_sentinal_t {
  template<class Rhs,
    std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
  >
  friend bool operator==(Rhs const& ptr, null_sentinal_t) {
    return !*ptr;
  }
  template<class Rhs,
    std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
  >
  friend bool operator!=(Rhs const& ptr, null_sentinal_t) {
    return !(ptr==null_sentinal_t{});
  }
  template<class Lhs,
    std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
  >
  friend bool operator==(null_sentinal_t, Lhs const& ptr) {
    return !*ptr;
  }
  template<class Lhs,
    std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
  >
  friend bool operator!=(null_sentinal_t, Lhs const& ptr) {
    return !(null_sentinal_t{}==ptr);
  }
  friend bool operator==(null_sentinal_t, null_sentinal_t) {
    return true;
  }
  friend bool operator!=(null_sentinal_t, null_sentinal_t) {
    return false;
  }
};

সম্পূর্ণ সি ++ 17 সমর্থন ছাড়াই সংকলকটিতে সরাসরি উদাহরণ ; forলুপটি ম্যানুয়ালি প্রসারিত।


যদি রেঞ্জ-ভিত্তিক কোনও ভিন্ন লক মেকানিজম ব্যবহার করে, তবে সম্ভবত এই রেঞ্জ-ভিত্তিক ব্যবস্থা করা সম্ভব যেটি কোডের জন্য পৃথক কোডের চেয়ে আলাদা কোড beginএবং endফাংশন পায় code সম্ভবত তখন তারা অন্যরকম আচরণ করার জন্য খুব বিশেষজ্ঞ হতে পারে (সর্বাধিক অনুকূলিতকরণ সম্ভব করার জন্য শেষ যুক্তি উপেক্ষা করে দ্রুত।
অ্যারন ম্যাকডেইড

পছন্দ করুন আপনি সহজেই আশ্চর্যজনক ফলাফল সহ শেষ করতে চাইবেন, কারণ কলিংয়ের কিছু উপায় শুরু / শেষের শুরু / শেষের জন্য পরিসীমা ভিত্তিক শেষ হবে এবং অন্যরা তা করবে না। অভিনব পরিবর্তন (ক্লায়েন্ট পক্ষ থেকে) আচরণ পরিবর্তন পেতে পারে।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

1
আপনি প্রয়োজন হবে না begin(X&&)। অস্থায়ীটি মাঝারি অবস্থায় স্থির করে auto&&একটি রেঞ্জ-ভিত্তিক দ্বারা , এবং beginসর্বদা একটি ল্যাভ্যু ( __range) দিয়ে ডাকা হয় ।
টিসি

2
এই উত্তরটি সত্যই কোনও টেম্পলেট উদাহরণ থেকে উপকৃত হবে যা কোনও অনুলিপি এবং প্রয়োগ করতে পারে।
টোমা জ্যাটো - মনিকা

আমি বরং পুনরাবৃত্তকারী ধরণের (*, ++,! =) বৈশিষ্ট্যগুলিতে চাপ দিতে চাই। আমার পুনরাবৃত্তি করতে আপনাকে এই উত্তরটি পুনরাবৃত্তি করতে বলা উচিত যাতে পুনরাবৃত্তিকারী টাইপ স্পেসকে আরও সাহসী করে তোলে।
রেড.ওয়েভ

62

আমি আমার উত্তরটি লিখছি কারণ কিছু লোকের মধ্যে এসটিএল না থাকলে সাধারণ বাস্তব জীবনের উদাহরণে আরও বেশি খুশি হতে পারে।

আমার কোনও কারণে আমার নিজস্ব প্লেইন ডেটা অ্যারে বাস্তবায়ন রয়েছে এবং আমি লুপের উপর ভিত্তি করে ব্যাপ্তিটি ব্যবহার করতে চেয়েছিলাম। এখানে আমার সমাধান:

 template <typename DataType>
 class PodArray {
 public:
   class iterator {
   public:
     iterator(DataType * ptr): ptr(ptr){}
     iterator operator++() { ++ptr; return *this; }
     bool operator!=(const iterator & other) const { return ptr != other.ptr; }
     const DataType& operator*() const { return *ptr; }
   private:
     DataType* ptr;
   };
 private:
   unsigned len;
   DataType *val;
 public:
   iterator begin() const { return iterator(val); }
   iterator end() const { return iterator(val + len); }

   // rest of the container definition not related to the question ...
 };

তারপরে ব্যবহারের উদাহরণ:

PodArray<char> array;
// fill up array in some way
for(auto& c : array)
  printf("char: %c\n", c);

2
উদাহরণটিতে শুরু () এবং শেষ () পদ্ধতি রয়েছে এবং এর সাথে একটি বেসিক (সহজেই বোঝার) উদাহরণ রয়েছে পুনরাবৃত্ত শ্রেণীর যা সহজেই কোনও কাস্টম ধারক প্রকারের জন্য সামঞ্জস্য করা যায়। স্টাড :: অ্যারে <> তুলনা এবং যে কোনও সম্ভাব্য বিকল্প বাস্তবায়ন একটি আলাদা প্রশ্ন এবং আমার মতে লুপের জন্য পরিসর-ভিত্তিক কোনও সম্পর্ক নেই।
সিজেপিটার

এটি একটি খুব সংক্ষিপ্ত এবং বাস্তব উত্তর! আমি ঠিক কী খুঁজছিলাম! ধন্যবাদ!
জ্যাক টেলর

1
এর const জন্য রিটার্ন কোয়ালিফায়ার অপসারণ করা কি আরও উপযুক্ত হবে const DataType& operator*()এবং ব্যবহারকারীকে ব্যবহার করতে const auto&বা বেছে দিতে দিন auto&? যাইহোক ধন্যবাদ, দুর্দান্ত উত্তর;)
রিক

53

মানটির প্রাসঙ্গিক অংশটি 6.5.4 / 1:

যদি _RangeT একটি শ্রেণির ধরণের হয় তবে অসাধারণ fi এড-আইডিগুলি শুরু হয় এবং শেষটি শ্রেণীর স্কোজে দেখা হয় _ শ্রেণিবদ্ধভাবে যেমন শ্রেণীর সদস্য অ্যাক্সেস লুক (4.৪.৫) দ্বারা, এবং যদি হয় (বা উভয়) least n অন্তত একটি ঘোষণা থাকে তবে শুরু করুন - এক্সপ্রেস এবং শেষ এক্সপ্রেস হয় __range.begin()এবং__range.end() যথাক্রমে ;

- অন্যথায়, শুরু-expr এবং শেষ-expr হয় begin(__range)এবং end(__range)যথাক্রমে, যেখানে শুরু এবং শেষ পর্যন্ত যুক্তি নির্ভর লুকআপ (3.4.2) সঙ্গে লাগছিল করছে। এই নামটির অনুসন্ধানের উদ্দেশ্যে, নেমস্পেস এসটিডি একটি যুক্ত নেমস্পেস।

সুতরাং, আপনি নিম্নলিখিত যে কোনও একটি করতে পারেন:

  • সংজ্ঞায়িত beginএবংend সদস্য ফাংশন
  • সংজ্ঞায়িত beginএবংend ফ্রি ফাংশনগুলি যা এডিএল দ্বারা সন্ধান করা হবে (সরলীকৃত সংস্করণ: এগুলি শ্রেণীর মতো একই নেমস্পেসে রাখুন)
  • বিশেষজ্ঞ std::beginএবংstd::end

std::beginbegin()যাইহোক সদস্যকে ফাংশন কল করে , সুতরাং যদি আপনি কেবল উপরের কোনওটি প্রয়োগ করেন, তবে ফলাফল আপনি পছন্দ করুন না কেন একই হওয়া উচিত। লুপগুলির জন্য রেঞ্জ-ভিত্তিক একই ফলাফল এবং কেবল মর্টাল কোডের জন্য একই ফলাফল যা তার নিজস্ব যাদুকরী নাম রেজোলিউশন নিয়ম না করে ঠিক তেমন using std::begin;কোনও অযোগ্য কল অনুসরণ করার পরেbegin(a)

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

আপনি যে জিনিসটি লিখছেন সেটি যদি কনটেইনার ইন্টারফেস প্রয়োগ করে, তবে এতে ইতিমধ্যে সদস্য সদস্য রয়েছে begin()এবং এটি end()যথেষ্ট পরিমাণে হওয়া উচিত। যদি এটি এমন একটি পরিসীমা থাকে যা কোনও ধারক না হয় (তবে এটির ধারণাটি ভাল হবে যদি তা পরিবর্তনযোগ্য না হয় বা আপনি যদি আকারটি সামনে না জানেন) তবে আপনি চয়ন করতে পারেন।

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


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

2
@ পাব্বি: .5.৫.৪ দেখে আমি মনে করি ইনপুটআইট্রেটর যথেষ্ট। তবে আসলে আমি মনে করি না যে প্রকারটি ফেরত পাঠানো হয়েছে তার জন্য পরিসর-ভিত্তিকের জন্য মোটামুটি একটি পুনরাবৃত্তি হওয়া উচিত। বিবৃতিটি স্ট্যান্ডার্ডে এটির সমতুল্য দ্বারা সংজ্ঞায়িত করা হয়, সুতরাং এটি কোডটিতে কেবলমাত্র ব্যবহৃত অভিব্যক্তিগুলি স্ট্যান্ডার্ডে প্রয়োগ করতে যথেষ্ট: অপারেটর !=, উপসর্গ ++এবং একরী *। এটা সম্ভবত এর অপরিণামদর্শী বাস্তবায়ন begin()এবং end()সদস্য ফাংশন বা অ- সদস্য ADL ফাংশন যে কোনো ইটারেটরে ছাড়া অন্য রিটার্ন কিছু, কিন্তু আমি মনে করি এটা বৈধতা পাবে। বিশেষ std::beginএকটি ফিরতে অ পুনরুক্তিকারীর UB, আমি মনে করি।
স্টিভ জেসোপ

আপনি কি নিশ্চিত যে std :: শুরু করা উচিত নয়? আমি জিজ্ঞাসা করি কারণ স্ট্যান্ডার্ড লাইব্রেরি কয়েকটি ক্ষেত্রে নিজেই এটি করে।
থ্রিবিট

@ থ্রিবিট: হ্যাঁ, আমি নিশ্চিত স্ট্যান্ডার্ড গ্রন্থাগার বাস্তবায়নের নিয়মগুলি প্রোগ্রামগুলির নিয়ম থেকে পৃথক।
স্টিভ জেসপ


34

আমি কি কেবল () শুরু এবং () শেষ করতে পারব?

আমি যতদূর জানি, এটি যথেষ্ট। আপনাকে এটিও নিশ্চিত করতে হবে যে পয়েন্টারটি বাড়ানো শুরু থেকে শেষ পর্যন্ত আসবে।

পরবর্তী উদাহরণ (এটি প্রারম্ভ এবং শেষের কনস্ট সংস্করণ অনুপস্থিত) সংকলন করে এবং সূক্ষ্মভাবে কাজ করে।

#include <iostream>
#include <algorithm>

int i=0;

struct A
{
    A()
    {
        std::generate(&v[0], &v[10], [&i](){  return ++i;} );
    }
    int * begin()
    {
        return &v[0];
    }
    int * end()
    {
        return &v[10];
    }

    int v[10];
};

int main()
{
    A a;
    for( auto it : a )
    {
        std::cout << it << std::endl;
    }
}

এখানে ফাংশন হিসাবে শুরু / শেষের সাথে আরও একটি উদাহরণ। তারা আছে ADL কারণে শ্রেণী হিসেবে একই নামস্থান হতে:

#include <iostream>
#include <algorithm>


namespace foo{
int i=0;

struct A
{
    A()
    {
        std::generate(&v[0], &v[10], [&i](){  return ++i;} );
    }

    int v[10];
};

int *begin( A &v )
{
    return &v.v[0];
}
int *end( A &v )
{
    return &v.v[10];
}
} // namespace foo

int main()
{
    foo::A a;
    for( auto it : a )
    {
        std::cout << it << std::endl;
    }
}

1
@ereOn একই নেমস্পেসে যেখানে ক্লাসটি সংজ্ঞায়িত করা হয়েছে। দ্বিতীয় উদাহরণটি দেখুন
BЈовић

2
অভিনন্দন পাশাপাশি :) এটি দ্বিতীয় উদাহরণের জন্য আর্গুমেন্ট ডিপেন্ডেন্ট লুকআপ (এডিএল) বা কোনিগ লুকআপ পদগুলি উল্লেখ করার মতো হতে পারে ( কেন ফ্রি ফাংশনটি যে শ্রেণীতে পরিচালিত হয় সেই একই নামস্থানে কেন হবে) তা বোঝানোর জন্য।
ম্যাথিউ এম।

1
@ অরিওন: আসলে, আপনি করবেন না। এডিএল আর্গুমেন্টের অন্তর্ভুক্ত নামের জায়গাগুলি স্বয়ংক্রিয়ভাবে অন্তর্ভুক্ত করার জন্য স্কোপগুলি সন্ধানের জন্য প্রসারিত করতে চলেছে। ওভারলোড রেজোলিউশন সম্পর্কে একটি ভাল এসিসিইউ নিবন্ধ রয়েছে , যা দুর্ভাগ্যক্রমে নাম অনুসন্ধান অংশটি এড়িয়ে চলে। নামের সন্ধানে প্রার্থীদের ফাংশন সংগ্রহ করা জড়িত, আপনি বর্তমান সুযোগ + আর্গুমেন্টের স্কোপগুলি দেখে শুরু করবেন। যদি সেই নামটির মিল খুঁজে পাওয়া যায় না, আপনি বর্তমান সুযোগের মূল স্কোপটিতে চলে যান এবং বিশ্বব্যাপী সুযোগে পৌঁছা পর্যন্ত আবার অনুসন্ধান করুন ...
ম্যাথিউ এম।

1
@ বিউ দুঃখিত, তবে কোন কারণে শেষ পর্যন্ত () ফাংশনটিতে আপনি কোনও বিপজ্জনক পয়েন্টারটি ফেরত দেবেন? আমি জানি এটি কাজ করে তবে আমি এর যুক্তি বুঝতে চাই। অ্যারের শেষটি v [9], আপনি কেন কখনও ভি [10] এ ফিরে আসবেন?
জ্যামমিয়াল

1
@gedamial আমি সম্মত আমার মনে হয় এটি হওয়া উচিত return v + 10&v[10]অ্যারের কাছাকাছি গিয়ে মেমরির অবস্থানটিকে অবহেলা করে।
মিলি স্মিথ

16

আপনি যদি কোনও শ্রেণীর পুনরাবৃত্তি সরাসরি std::vectorবা তার std::mapসদস্যের সাথে ফিরে পেতে চান তবে তার জন্য কোডটি এখানে:

#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <map>
using std::map;


/////////////////////////////////////////////////////
/// classes
/////////////////////////////////////////////////////

class VectorValues {
private:
    vector<int> v = vector<int>(10);

public:
    vector<int>::iterator begin(){
        return v.begin();
    }
    vector<int>::iterator end(){
        return v.end();
    }
    vector<int>::const_iterator begin() const {
        return v.begin();
    }
    vector<int>::const_iterator end() const {
        return v.end();
    }
};

class MapValues {
private:
    map<string,int> v;

public:
    map<string,int>::iterator begin(){
        return v.begin();
    }
    map<string,int>::iterator end(){
        return v.end();
    }
    map<string,int>::const_iterator begin() const {
        return v.begin();
    }
    map<string,int>::const_iterator end() const {
        return v.end();
    }

    const int& operator[](string key) const {
        return v.at(key);
    }
    int& operator[](string key) {
        return v[key];
    } 
};


/////////////////////////////////////////////////////
/// main
/////////////////////////////////////////////////////

int main() {
    // VectorValues
    VectorValues items;
    int i = 0;
    for(int& item : items) {
        item = i;
        i++;
    }
    for(int& item : items)
        cout << item << " ";
    cout << endl << endl;

    // MapValues
    MapValues m;
    m["a"] = 1;
    m["b"] = 2;
    m["c"] = 3;
    for(auto pair: m)
        cout << pair.first << " " << pair.second << endl;
}

2
এটি এতই কহতব্য const_iteratorএছাড়াও একটি ইন অ্যাক্সেস করা যেতে পারে autoমাধ্যমে (সি ++ 11) -compatible পথ cbegin, cendইত্যাদি
underscore_d

2

এখানে আমি কাস্টম প্রকার তৈরির সহজতম উদাহরণটি ভাগ করছি, এটি " লুপের জন্য পরিসীমা-ভিত্তিক " সাথে কাজ করবে :

#include<iostream>
using namespace std;

template<typename T, int sizeOfArray>
class MyCustomType
{
private:
    T *data;
    int indx;
public:
    MyCustomType(){
        data = new T[sizeOfArray];
        indx = -1;
    }
    ~MyCustomType(){
        delete []data;
    }
    void addData(T newVal){
        data[++indx] = newVal;
    }

    //write definition for begin() and end()
    //these two method will be used for "ranged based loop idiom"
    T* begin(){
        return &data[0];
    }
    T* end(){
        return  &data[sizeOfArray];
    }
};
int main()
{
    MyCustomType<double, 2> numberList;
    numberList.addData(20.25);
    numberList.addData(50.12);
    for(auto val: numberList){
        cout<<val<<endl;
    }
    return 0;
}

আশা করি, এটি আমার মতো কিছু নবজাতক বিকাশকারীকে সহায়ক হবে: পি :)
আপনাকে ধন্যবাদ।


আপনার শেষ পদ্ধতিতে অবৈধ মেমরিটিকে অধিবেশন এড়াতে কেন একটি অতিরিক্ত উপাদান বরাদ্দ করবেন না?
অ্যান্ডারসকে

@ এন্ডার্স কারণ প্রায় সমস্ত প্রান্ত-পুনরুক্তিকারীগুলি তাদের সমন্বিত কাঠামোর সমাপ্তির পরে নির্দেশ করে । end()ফাংশন নিজেই স্পষ্টত যেহেতু এটি শুধুমাত্র এই মেমরি অবস্থানকে 'অফ ঠিকানা' লাগে, একটি অনুপযুক্ত মেমরি অবস্থানকে ডি-রেফারেন্স না। অতিরিক্ত উপাদান যুক্ত করার অর্থ হ'ল আপনার আরও স্মৃতি দরকার এবং your_iterator::end()যে কোনও উপায়ে এই মানটি যে কোনওরকম পুনরুক্তিকারীদের সাথে কাজ করবে না কারণ এটি একইভাবে নির্মিত are
কিউকিউই

@ কিউউই তার শেষ পদ্ধতিটি ডি-রিফ্রান্সগুলি - return &data[sizeofarray]এটি ঠিক যে ঠিকানার তথ্য + আকার আকারের ফিরিয়ে দেওয়া উচিত তবে আমি কী জানি,
অ্যান্ডারসেকে

@ আন্ডারস আপনি সঠিক আমাকে ধারালো রাখার জন্য ধন্যবাদ :-)। হ্যাঁ, data + sizeofarrayএটি লেখার সঠিক উপায় হবে।
কিউকিউই

1

ক্রিস রেডফোর্ডের উত্তর কিউটি পাত্রে (অবশ্যই) কাজ করে। এখানে একটি অভিযোজন দেওয়া হয়েছে ( কনস্ট_াইটেরেটর পদ্ধতি থেকে constBegin()যথাক্রমে আমি একটি ফেরত বিজ্ঞপ্তি দিয়েছি constEnd()):

class MyCustomClass{
    QList<MyCustomDatatype> data_;
public:    
    // ctors,dtor, methods here...

    QList<MyCustomDatatype>::iterator begin() { return data_.begin(); }
    QList<MyCustomDatatype>::iterator end() { return data_.end(); }
    QList<MyCustomDatatype>::const_iterator begin() const{ return data_.constBegin(); }
    QList<MyCustomDatatype>::const_iterator end() const{ return data_.constEnd(); }
};

0

আমি @ স্টিভ জেসপের উত্তরের কয়েকটি অংশ বিস্তারিতভাবে বলতে চাই, যার জন্য প্রথমে আমি বুঝতে পারি নি। আশা করি এটা সাহায্য করবে.

std::beginbegin()যাইহোক যাইহোক সদস্য ফাংশনটিকে কল করে , সুতরাং আপনি যদি কেবল উপরের কোনওটি প্রয়োগ করেন, তবে ফলাফল আপনি পছন্দ করুন না কেন একই হওয়া উচিত। যে জন্য loops জন্য সীমাকৃত ভিত্তিক একই ফলাফল, এবং তার নিজস্ব ঐন্দ্রজালিক নাম রেজল্যুশন নিয়ম তাই ঠিক নেই নেই যে নিছক মরণশীল কোড একই ফলাফল এর using std::begin;একটি অযোগ্য কল দ্বারা অনুসৃত begin(a)

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


https://en.cppreferences.com/w/cpp/language/range- জন্য :

  • যদি ...
  • যদি range_expressionকোনও শ্রেণীর প্রকারের প্রকাশ হয় Cযার সদস্য beginএবং নামপ্রাপ্ত সদস্য উভয় থাকে end(যেমন সদস্যের প্রকার বা অ্যাক্সেসযোগ্যতা নির্বিশেষে) তবে begin_exprহয় __range.begin() এবং end_exprহয় __range.end();
  • অন্যথায়, begin_exprহ'ল begin(__range)এবং end_exprহ'ল end(__range), যা আর্গুমেন্ট-নির্ভর লুকআপের মাধ্যমে পাওয়া যায় (নন-এডিএল লুকআপ সম্পাদন করা হয় না)।

লুপের জন্য পরিসীমা ভিত্তিক জন্য, সদস্য ফাংশনগুলি প্রথমে নির্বাচিত হয়।

না হইলে

using std::begin;
begin(instance);

ADL ফাংশনগুলি প্রথমে নির্বাচিত হয়।


উদাহরণ:

#include <iostream>
#include <string>
using std::cout;
using std::endl;

namespace Foo{
    struct A{
        //member function version
        int* begin(){
            cout << "111";
            int* p = new int(3);  //leak I know, for simplicity
            return p;
        }
        int *end(){
            cout << "111";
            int* p = new int(4);
            return p;
        }
    };

    //ADL version

    int* begin(A a){
        cout << "222";
        int* p = new int(5);
        return p;
    }

    int* end(A a){
        cout << "222";
        int* p = new int(6);
        return p;
    }

}

int main(int argc, char *args[]){
//    Uncomment only one of two code sections below for each trial

//    Foo::A a;
//    using std::begin;
//    begin(a);  //ADL version are selected. If comment out ADL version, then member functions are called.


//      Foo::A a;
//      for(auto s: a){  //member functions are selected. If comment out member functions, then ADL are called.
//      }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.