লুপের উপর ভিত্তি করে রেঞ্জের সাথে ব্যবহারের জন্য কি সি ++ 11 তে একটি শ্রেণি শ্রেণি রয়েছে?


101

আমি নিজেকে এই লিখতে পেয়েছি একটু আগেই:

template <long int T_begin, long int T_end>
class range_class {
 public:
   class iterator {
      friend class range_class;
    public:
      long int operator *() const { return i_; }
      const iterator &operator ++() { ++i_; return *this; }
      iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }

      bool operator ==(const iterator &other) const { return i_ == other.i_; }
      bool operator !=(const iterator &other) const { return i_ != other.i_; }

    protected:
      iterator(long int start) : i_ (start) { }

    private:
      unsigned long i_;
   };

   iterator begin() const { return iterator(T_begin); }
   iterator end() const { return iterator(T_end); }
};

template <long int T_begin, long int T_end>
const range_class<T_begin, T_end>
range()
{
   return range_class<T_begin, T_end>();
}

এবং এটি আমাকে এই জাতীয় জিনিস লিখতে দেয়:

for (auto i: range<0, 10>()) {
    // stuff with i
}

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

তাই না? পুনরাবৃত্তির জন্য কিছু সংখ্যক পূর্ণসংখ্যার পূর্ণসংখ্যার জুড়ে নতুন গ্রন্থাগার যুক্ত করা হয়েছিল, বা গণিত স্কেলারের মানগুলির জেনেরিক পরিসর?


17
+1 টি। আমি আমার ইউটিলিটিগুলিতে এই জাতীয় ক্লাস রাখতে চাই। :-)
নওয়াজ

2
যাইহোক, rangeটেমপ্লেট ফাংশন লেখার বিন্দুটি কী ? এটি যে ব্যবহারে range_classব্যবহৃত হয় তাতে কোনও কিছুই যুক্ত করে না । মানে, range<0,10>()আর range_class<0,10>()দেখতে ঠিক একই!
নওয়াজ

2
@ নাওয়াজ: হ্যাঁ, আপনি ঠিক বলেছেন। আমার কিছু অদ্ভুত দৃষ্টি ছিল যা আমি গতিশীল এবং স্ট্যাটিক কেসের মধ্যে পার্থক্যটি ফাংশন হ্যান্ডেল করতে পারি, তবে আমি মনে করি না এটি করা সম্ভব।
সর্বাত্মক

2
@ আইয়ামিলিন্ড: নওয়াজ একই প্রশ্ন জিজ্ঞাসা করেছিলেন আপনার থেকে 35 মিনিট আগে;)
সেবাস্তিয়ান মাচ

3
পেডেন্টিক হওয়ার জন্য আমি মনে করি এই বাস্তবায়নের একটি বাগ রয়েছে, এটি হ'ল আপনি এটি পুরো সংখ্যার পরিসীমাতে পুনরাবৃত্তি করতে ব্যবহার করতে পারবেন না। যদি আপনি আপনার টেম্পলেট আর্গুমেন্ট হিসাবে INT_MIN এবং INT_MAX প্লাগ ইন করেন, বর্ধিত হওয়ার পরে INT_MAX উপচে পড়বে INT_MIN দেবে এবং অসীম লুপের কারণ হবে। এসটিএলে "শেষ" হ'ল "শেষের এক শেষ" হওয়ার কথা যা এটি পূর্ণসংখ্যার ধরণের ভিতরেই ফিট করতে পারে না, তাই আমি জানি না যে এটি কোনও নির্দিষ্ট প্ল্যাটফর্মে বিস্তৃত পূর্ণসংখ্যার ধরণের জন্য আসলে কার্যকরভাবে প্রয়োগ করা যেতে পারে। ছোট পূর্ণসংখ্যার প্রকারের জন্য আপনি সর্বদা অভ্যন্তরীণভাবে এটি আরও বিস্তৃত প্রকারের ব্যবহার করতে পারেন ...
জোসেফ গারভিন

উত্তর:


59

সি ++ স্ট্যান্ডার্ড লাইব্রেরির একটি নেই, তবে বুস্ট.রেঞ্জের :: গণনা_আরঞ্জের উন্নতি হয়েছে , যা অবশ্যই যোগ্যতা অর্জন করে। আপনি বুস্ট :: ইরঞ্জও ব্যবহার করতে পারেন যা স্কোপটিতে কিছুটা বেশি কেন্দ্রীভূত।

সি ++ 20 এর রেঞ্জের লাইব্রেরি আপনাকে এই মাধ্যমে এটি করার অনুমতি দেবে view::iota(start, end)


3
হ্যাঁ, আমি অবশ্যই যা খুঁজছিলাম তার প্রকৃতি এটি অবশ্যই। আমি খুশি বুস্ট এটি করেছে। আমি দুঃখিত যে স্ট্যান্ডার্ড কমিটি এটিকে কোনও কারণে অন্তর্ভুক্ত করেনি। এটি পরিসীমা-বেস-বৈশিষ্ট্যটির দুর্দান্ত পরিপূরক হত।
সর্বাত্মক

এই উত্তরটি আমার সরাসরি প্রশ্নের উত্তর দেয়, এবং তাই আমি এটি নির্বাচন করব, যদিও নওয়াজের উত্তর খুব ভাল।
সর্বাত্মক

6
স্ট্যান্ডার্ড (N4128) এ রেঞ্জ পেতে ইদানীং অনেক অগ্রগতি হয়েছে। প্রস্তাব এবং রেফারেন্স বাস্তবায়নের জন্য github.com/ericniebler/range-v3 দেখুন ।
এলা 782

1
@ ইলা 782: ... এবং তবুও মনে হচ্ছে আমরা এটি সি ++ 17 এ দেখব না, তাই না?
einpoklum

1
@ আন্ড্রেয়াস হ্যাঁ, রেঞ্জগুলি কিছুক্ষণ আগে এটিকে একটি টিএস হিসাবে তৈরি করেছিল, তবে আমি মনে করি না যে কোনও রেফারেন্স বাস্তবায়ন আছে / যা এটি স্থানের অধীনে প্রধান সংকলকগুলিতে পরিণত হয়েছিল std::experimental::rangesrange-v3রেফারেন্স বাস্তবায়নটি আমি সর্বদা সাজতাম। তবে এখন আমি বিশ্বাস করি যে মৌলিক পরিসরের স্টাফগুলিকেও সম্প্রতি সি ++ ২০ তে ভোট দেওয়া হয়েছে, সুতরাং আমরা std::শীঘ্রই তা পেয়ে যাব ! :-)
Ela782

47

আমি যতদূর জানি, সি ++ 11 এ তেমন কোনও শ্রেণি নেই।

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

//your version
auto x = range<m,n>(); //m and n must be known at compile time

//my version
auto x = range(m,n);  //m and n may be known at runtime as well!

কোডটি এখানে:

class range {
 public:
   class iterator {
      friend class range;
    public:
      long int operator *() const { return i_; }
      const iterator &operator ++() { ++i_; return *this; }
      iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }

      bool operator ==(const iterator &other) const { return i_ == other.i_; }
      bool operator !=(const iterator &other) const { return i_ != other.i_; }

    protected:
      iterator(long int start) : i_ (start) { }

    private:
      unsigned long i_;
   };

   iterator begin() const { return begin_; }
   iterator end() const { return end_; }
   range(long int  begin, long int end) : begin_(begin), end_(end) {}
private:
   iterator begin_;
   iterator end_;
};

পরীক্ষার কোড:

int main() {
      int m, n;
      std::istringstream in("10 20");
      if ( in >> m >> n ) //using in, because std::cin cannot be used at coliru.
      {
        if ( m > n ) std::swap(m,n); 
        for (auto i : range(m,n)) 
        {
             std::cout << i << " ";
        }
      }
      else 
        std::cout <<"invalid input";
}

আউটপুট:

10 11 12 13 14 15 16 17 18 19 19

Onine ডেমো


3
আমি এটা পছন্দ করি. আমি একটি টেমপ্লেটবিহীন সংস্করণ সম্পর্কে ভেবেছিলাম। এবং আমি মনে করি যে কোনও ভাল সংকলক যখন মানগুলি স্থির থাকে তখন ক্ষেত্রে এটি ভালভাবে অনুকূলিত হবে। আমি এটি পরীক্ষা করতে হবে।
সর্বক্ষমতার

10
@Nawaz: আমি এখনও এটা টেমপ্লেট চাই, অবিচ্ছেদ্য ধরনের উপর :) আমিও ওরফে প্রস্তাব চাই iteratorথেকে const_iterator, have iteratorথেকে আহরণ করা std::iteratorএবং rangeবাস্তবায়ন cbeginএবং cend। ওহ আর ... কেন iterator::operator++একটি আয় const রেফারেন্স?
ম্যাথিউ এম।

6
@RedX: Dijkstra একটি ভাল লেখার আপ কেন পরিসীমা লেবেল শ্রেষ্ঠ হিসাবে উপর রয়েছে [begin, end)। @ ওপেন: রেঞ্জ-ভিত্তিক লুপগুলিতে শ্লেষের জন্য +1 করুন যা কোনও পাং নয় :-)
কেরেক এসবি

2
নন-টেম্পলেট সংস্করণটির সুবিধা হ'ল সংকলনের সময় আপনার লুপগুলির দৈর্ঘ্য জানা দরকার। আপনি অবশ্যই পূর্ণসংখ্যার টাইপকে টেম্পলেট করে দিতে পারেন।
ক্যাশকো

2
@ ওয়েসকা: এই ওভারলোডটি পোস্টফিক্স ইনক্রিমেন্ট বাস্তবায়নের কথা বলেছে v++যা বর্ধিত ক্রিয়াকলাপ শুরুর আগে মানটি ফেরত দেবে বলে মনে করা হচ্ছে । আমি আপনাকে পরামর্শ দিচ্ছি যে কোথায় ++iএবং i++কোথায় iঘোষিত হয়েছে তার মধ্যে পার্থক্যটি সন্ধান করতে int
নওয়াজ

13

আমি একটি লাইব্রেরি লিখেছিলাম যা rangeঠিক একই উদ্দেশ্যে ডাকা একটি রান-টাইম পরিসীমা ব্যতীত, এবং আমার ক্ষেত্রে ধারণাটি পাইথন থেকে এসেছিল। আমি একটি সংকলন-সময় সংস্করণ বিবেচনা করেছি, তবে আমার নম্র মতে সংকলন-কালীন সংস্করণটি অর্জন করার কোনও সত্যিকারের সুবিধা নেই। আপনি বিটবাকেটে লাইব্রেরিটি খুঁজে পেতে পারেন এবং এটি বুস্ট লাইসেন্স: রেঞ্জের আওতায় রয়েছে । এটি একটি ওয়ান-হেডার লাইব্রেরি, সি ++ 03 এর সাথে সামঞ্জস্যপূর্ণ এবং সি ++ 11 এ লুপের জন্য পরিসর-ভিত্তিক মনোযোগের মতো কাজ করে :)

বৈশিষ্ট্য :

  • সমস্ত ঘন্টা এবং শিসিসহ একটি সত্য র্যান্ডম অ্যাক্সেস ধারক!

  • পরিসীমা লিক্সোগ্রাফিকভাবে তুলনা করা যেতে পারে।

  • একটি সংখ্যার অস্তিত্ব পরীক্ষা করার জন্য দুটি ফাংশন exist(রিটার্ন বুল) এবং find(পুনরাবৃত্তি পুনরায়)

  • লাইব্রেরিটি ক্যাচটি ব্যবহার করে ইউনিট-টেস্ট করা হয়েছে ।

  • বেসিক ব্যবহারের উদাহরণ, স্ট্যান্ডার্ড পাত্রে কাজ করা, স্ট্যান্ডার্ড অ্যালগরিদমগুলির সাথে কাজ করা এবং লুপগুলির জন্য ভিত্তিক পরিসরের সাথে কাজ করা।

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


এক মিনিটের ভূমিকাটি বলে যে উইকিতে আমার অ্যাক্সেস নেই। আপনার উইকিকে সর্বজনীন করা দরকার।
নিকল বোলাস

@ নিকোল বোলাস আমি সত্যিই দুঃখিত, এটি এখন প্রকাশ্য :)
আরাক

এই জন্য আপনাকে ধন্যবাদ, এটি আশ্চর্যজনক। আমার মনে হয় আরও বেশি লোকের সম্পর্কে এটি জানা উচিত।
রাফায়েল কিটওভার

5

আমি দেখতে পেয়েছি যে boost::irangeক্যানোনিকাল পূর্ণসংখ্যার লুপের চেয়ে অনেক ধীর ছিল। সুতরাং আমি একটি প্রাক প্রসেসর ম্যাক্রো ব্যবহার করে নিম্নলিখিত অনেক সহজ সমাধানে স্থির হয়েছি:

#define RANGE(a, b) unsigned a=0; a<b; a++

তারপরে আপনি এটির মতো লুপ করতে পারেন:

for(RANGE(i, n)) {
    // code here
}

এই ব্যাপ্তিটি স্বয়ংক্রিয়ভাবে শূন্য থেকে শুরু হয়। এটি কোনও প্রদত্ত নম্বর থেকে শুরু করার জন্য সহজেই বাড়ানো যেতে পারে।


7
লক্ষ করুন যা for (RANGE(i, flag? n1: n2))অবাক করে দেওয়ার ফলাফল দেবে, কারণ আপনি নন-এভিল ম্যাক্রোসের বেসিক বিধিগুলির একটি অনুসরণ করতে ব্যর্থ হয়েছেন, যা আপনার সমস্ত পরামিতিগুলি বন্ধনীরূপে করা (এই ক্ষেত্রে, সহ b)। আপনার পদ্ধতিটি অ-ম্যাক্রো, "রেঞ্জ অবজেক্ট" ভিত্তিক পদ্ধতির (যেমন নওয়াজের উত্তর ) উপর কোনও কার্যকারিতা সুবিধা দেয় না ।
কুইকসপ্লসোন

2

এখানে একটি সহজ ফর্ম যা আমার জন্য সুন্দরভাবে কাজ করছে। আমার পদ্ধতির মধ্যে কি কোনও ঝুঁকি রয়েছে?

r_iteratorএকটি ধরনের যা আচরণ করে, যতটা সম্ভব, ক এর মতো long int। সুতরাং অনেক অপারেটর যেমন ==এবং ++, কেবল এর মধ্য দিয়ে যায় long int। আমি 'এক্সপোজ' মাধ্যমে অন্তর্নিহিত দীর্ঘ int- এ operator long intএবং operator long int &ধর্মান্তর।

#include <iostream>
using namespace std;

struct r_iterator {
        long int value;
        r_iterator(long int _v) : value(_v) {}
        operator long int () const { return value; }
        operator long int& ()      { return value; }
        long int operator* () const { return value; }
};
template <long int _begin, long int _end>
struct range {
        static r_iterator begin() {return _begin;}
        static r_iterator end  () {return _end;}
};
int main() {
        for(auto i: range<0,10>()) { cout << i << endl; }
        return 0;
}

( সম্পাদনা করুন: - আমরা rangeস্থির পরিবর্তে স্থির পদ্ধতিগুলি তৈরি করতে পারি ))


1

এটি হয়ত একটু দেরীতে হতে পারে তবে আমি এই প্রশ্নটি দেখেছি এবং আমি এই ক্লাসটি ব্যবহার করছি কিছু সময়ের জন্য:

#include <iostream>
#include <utility>
#include <stdexcept>

template<typename T, bool reverse = false> struct Range final {
    struct Iterator final{
        T value;
        Iterator(const T & v) : value(v) {}
        const Iterator & operator++() { reverse ? --value : ++value; return *this; }
        bool operator!=(const Iterator & o) { return o.value != value; }
        T operator*() const { return value; }
    };
    T begin_, end_;
    Range(const T & b, const T & e)  : begin_(b), end_(e) {
        if(b > e) throw std::out_of_range("begin > end");
    }

    Iterator begin() const { return reverse ? end_ -1 : begin_; }
    Iterator end() const { return reverse ? begin_ - 1: end_; }

    Range() = delete;
    Range(const Range &) = delete;
};

using UIntRange = Range<unsigned, false>;
using RUIntRange = Range<unsigned, true>;

ব্যবহার:

int main() {
    std::cout << "Reverse : ";
    for(auto i : RUIntRange(0, 10)) std::cout << i << ' ';
    std::cout << std::endl << "Normal : ";
    for(auto i : UIntRange(0u, 10u)) std::cout << i << ' ';
    std::cout << std::endl;
}

0

আপনি ব্যবহার চেষ্টা করেছেন?

template <class InputIterator, class Function>
   Function for_each (InputIterator first, InputIterator last, Function f);

বেশিরভাগ সময় বিলে খাপ খায়।

যেমন

template<class T> void printInt(T i) {cout<<i<<endl;}
void test()
{
 int arr[] = {1,5,7};
 vector v(arr,arr+3);

 for_each(v.begin(),v.end(),printInt);

}

নোট করুন যে মুদ্রণ আইটিকে সি ++ 0x এ ল্যাম্বডা দিয়ে প্রতিস্থাপন করা যেতে পারে। এছাড়াও এই ব্যবহারের আরও একটি ছোট পার্থক্য হতে পারে (এলোমেলো_আরেটরের জন্য কঠোরভাবে)

 for_each(v.begin()+5,v.begin()+10,printInt);

কেবল Fwd এর পুনরাবৃত্তির জন্য

 for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);

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

1
হ্যাঁ বলবে, তবে আপনি যদি উত্তরটি সঠিকভাবে ব্যবহার করার জন্য মনে করেন তবে আপনি উত্তরটি গ্রহণ করবেন। : পি মজা করা। ইতিমধ্যে উদাহরণ পোস্ট করেছেন।
অজিত গঙ্গা

আপনি এখানে ল্যাম্বডা ব্যবহার করতে পারেন তাই অটো পরিসীমা = myMલ્ટMap.equal_range (কী); ফর_ইচ (রেঞ্জ.ফার্স্ট, রেঞ্জ.সেকেন্ড, [&] (ডিক্লাইপ (* রেঞ্জ.ফার্স্ট) কনস্ট এবং আইটেম) {// কোড এখানে যায়});
ক্যাশকো

-3

আপনি সহজেই st + :: iota () ব্যবহার করে সি ++ 11 এ একটি ক্রমবর্ধমান ক্রম উত্পাদন করতে পারেন:

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>

template<typename T>
std::vector<T> range(T start, T end)
{
  std::vector<T> r(end+1-start, T(0));
  std::iota(r.begin(), r.end(), T(start));//increasing sequence
  return r;
}

int main(int argc, const char * argv[])
{
  for(auto i:range<int>(-3,5))
    std::cout<<i<<std::endl;

  return 0;
}

3
rangeবর্গ পরিসীমা মডেল হইবে। তবে আপনি আক্ষরিকভাবে এটি নির্মাণ করছেন। এটি মেমরি এবং স্মৃতি অ্যাক্সেসগুলির অপচয় waste সমাধানটি অত্যন্ত অপ্রয়োজনীয়, কারণ ভেক্টর উপাদানগুলির সংখ্যা এবং প্রথম উপাদানটির মান (যদি তা বিদ্যমান থাকে) ব্যতীত কোনও আসল তথ্য রাখে না।
এক-ব্যবহারকারী নয় 15

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