আমি কীভাবে একটি এনামের মাধ্যমে পুনরাবৃত্তি করতে পারি?


302

আমি কেবল লক্ষ্য করেছি যে আপনি একটি এনাম যেমন ++ বা + = তে স্ট্যান্ডার্ড গণিত অপারেটর ব্যবহার করতে পারবেন না

সুতরাং একটি সি ++ এনামের সমস্ত মানগুলির মাধ্যমে পুনরাবৃত্তি করার সর্বোত্তম উপায় কী?


2
অনেকগুলি পদ্ধতির মধ্যে একটি: যখন এনাম কেবলমাত্র যথেষ্ট নয়: সি ++ এর জন্য গণনা ক্লাস । এবং, আপনি যদি আরও কিছু সজ্জিত করতে চান তবে জেমস কানজে থেকে এই পদ্ধতির চেষ্টা করুন ।
ডন ওয়েকফিল্ড 16

সংযুক্ত আইটেমগুলির কিছু আকর্ষণীয় প্রতিক্রিয়া রয়েছে।
টনি

এই উত্তরগুলি এমন সমস্যাটিকে কাভার করে বলে মনে হচ্ছে না যা intযথেষ্ট বড় নাও হতে পারে! ( [C++03: 7.2/5])
অরবিট

মজার বিষয় হল, আপনি operator++এনামগুলিতে সংজ্ঞা দিতে পারেন ; তবে, তাই আপনি করতে পারেন for(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++)। নোট আপনি কাস্ট 0করতে হবে Enum_Eকারণ সি ++ enums মধ্যে অ্যাসাইনমেন্ট অপারেটরদের নিষেধ করে।
weberc2

যদি আকারের কাজগুলির মতোই একটি সংকলন টাইম অপারেটর থাকত, যা এনডির মানগুলি নিয়ে একটি স্টাড :: ইনিশিয়াল_লিস্টের আক্ষরিক নির্গমন করতে পারে তবে আমাদের সমাধান হবে এবং কোনও রানটাইম ওভারহেড জড়িত না।
jbruni

উত্তর:


263

সাধারণ উপায়টি নিম্নরূপ:

enum Foo {
  One,
  Two,
  Three,
  Last
};

for ( int fooInt = One; fooInt != Last; fooInt++ )
{
   Foo foo = static_cast<Foo>(fooInt);
   // ...
}

অনুগ্রহ করে নোট করুন, এনামটি Lastপুনরাবৃত্তি দ্বারা এড়িয়ে যাওয়া বোঝানো হয়েছে। এই "নকল" Lastএনাম ব্যবহার করে , আপনি প্রতিটি বার নতুন এনাম যুক্ত করতে চাইলে আপনাকে আপনার শেষ শর্তটি শেষ "রিয়েল" এনামে শেষ করতে হবে না। আপনি যদি পরে আরও এনাম যুক্ত করতে চান তবে কেবল শেষের আগে এগুলি যুক্ত করুন। এই উদাহরণে লুপটি এখনও কাজ করবে।

অবশ্যই এনাম মান নির্দিষ্ট করা থাকলে এটি ভেঙে যায়:

enum Foo {
  One = 1,
  Two = 9,
  Three = 4,
  Last
};

এটি চিত্রিত করে যে একটি এনাম সত্যিকার অর্থে পুনরাবৃত্তি করার জন্য নয়। একটি এনামের সাথে ডিল করার সাধারণ উপায়টি এটি একটি স্যুইচ বিবৃতিতে ব্যবহার করা।

switch ( foo )
{
    case One:
        // ..
        break;
    case Two:  // intentional fall-through
    case Three:
        // ..
        break;
    case Four:
        // ..
        break;
     default:
        assert( ! "Invalid Foo enum value" );
        break;
}

আপনি যদি সত্যিই গণনা করতে চান তবে এনাম মানগুলিকে একটি ভেক্টরে স্টাফ করুন এবং তার উপর পুনরাবৃত্তি করুন। এটি নির্দিষ্টভাবে এনাম মানগুলিও যথাযথভাবে মোকাবেলা করবে।


13
মনে রাখবেন যে, উদাহরণের প্রথম অংশে, আপনি যদি 'i' কে Foo enum হিসাবে ব্যবহার করতে চান এবং কোনও int নয়, আপনাকে এটি স্ট্যাটিক কাস্ট করতে হবে: স্ট্যাটিক_কাস্ট <ফু> (i)
ক্লেটন

5
এছাড়াও আপনি শেষ লুপ এড়িয়ে যাচ্ছেন। হওয়া উচিত <= শেষ
টনি

20
@ টনি লাস্ট এড়িয়ে যাওয়া বোঝানো হয়েছে। আপনি যদি পরে আরও এনাম যুক্ত করতে চান তবে শেষের আগে এগুলি যুক্ত করুন ... প্রথম উদাহরণের লুপটি এখনও কাজ করবে। একটি "নকল" সর্বশেষ এনাম ব্যবহার করে, আপনি প্রতিবার নতুন এনাম যুক্ত করতে চাইলে আপনাকে আপনার শেষের শর্তটি শেষ "রিয়েল" এনামে শেষ করতে হবে না।
টিমডিপিউও

এখন ব্যতীত আপনি আসলে মেমরি বরাদ্দ করেছেন যখন কোনও এনাম, শূন্য-সূচকযুক্ত এবং কঠোরভাবে অবিচল থাকে, মেমরির বরাদ্দ না করেই এই কাজটি করতে পারে।
মেঘ 23

1
নোট করুন যে এই এনাম সংজ্ঞা আপডেটের জন্য নিরাপদ থাকার জন্য একটির মান নির্ধারণ করা উচিত UNKNOWN = 0। অতিরিক্ত হিসাবে, আমি defaultএনাম মানগুলিতে স্যুইচ করার সময় কেবল কেসটি ড্রপ করার পরামর্শ দেব কারণ এটি এমন ক্ষেত্রে লুকিয়ে থাকতে পারে যেখানে রানটাইম অবধি মানগুলি পরিচালনা করা ভুলে গিয়েছিল। পরিবর্তে একের সকল মানকে হার্ডকোড করা উচিত এবং UNKNOWNঅসম্পূর্ণতাগুলি সনাক্ত করতে ক্ষেত্রটি ব্যবহার করা উচিত ।
বেনজামিন ব্যানিয়ার

53
#include <iostream>
#include <algorithm>

namespace MyEnum
{
  enum Type
  {
    a = 100,
    b = 220,
    c = -1
  };

  static const Type All[] = { a, b, c };
}

void fun( const MyEnum::Type e )
{
  std::cout << e << std::endl;
}

int main()
{
  // all
  for ( const auto e : MyEnum::All )
    fun( e );

  // some
  for ( const auto e : { MyEnum::a, MyEnum::b } )
    fun( e );

  // all
  std::for_each( std::begin( MyEnum::All ), std::end( MyEnum::All ), fun );

  return 0;
}

ধন্যবাদ! মনে রাখবেন আপনি যদি ফাইল / ক্লাসগুলি অতিক্রম করে থাকেন এবং যদি এমএসের সামঞ্জস্যতা আপনাকে শিরোনাম-ঘোষিত অ-পূর্ণসংখ্যক ধ্রুবকগুলির সাথে সমস্যাগুলি সরবরাহ করে, তবে এটি আমার সংকলকের অধীনে শিরোনামের ধরণটিকে স্পষ্টভাবে আকারে রাখতে সহায়তা করে: static const Type All[3];এবং তারপরে আমি সক্ষম উত্সে আরম্ভ করার জন্য: এটি const MyEnum::Type MyEnum::All[3] = { a, b, c }; করার আগে, আমি অশোভন Error in range-based for...ত্রুটিগুলি পাচ্ছিলাম (কারণ অ্যারের অজানা আকার ছিল)। আউট ধন্যবাদ এই মূর্ত একটি সম্পর্কিত উত্তর
ঋষি

1
অ্যারে সংস্করণটি কপি পেস্টের জন্য খুব বন্ধুত্বপূর্ণ। "NO" বা "কেবলমাত্র অনুক্রমের জন্য" ছাড়াও সবচেয়ে সন্তোষজনক উত্তর। সম্ভবত ম্যাক্রো বন্ধুত্বপূর্ণ।
পাওলো নেভেস

1
এটি অল্প সংখ্যক আইটেমযুক্ত এনগ্রামগুলির জন্য একটি ভাল সমাধান হতে পারে, তবে বিপুল সংখ্যক আইটেমযুক্ত এনামদের জন্য এটি অবশ্যই উপযুক্ত হবে না।
kato2

20

যদি আপনার এনাম 0 দিয়ে শুরু হয় এবং বর্ধন সবসময় 1 হয়।

enum enumType 
{ 
    A = 0,
    B,
    C,
    enumTypeEnd
};

for(int i=0; i<enumTypeEnd; i++)
{
   enumType eCurrent = (enumType) i;            
}

যদি না হয় তবে আমি কেবল অনুমান করি যে কেন এমন কিছু তৈরি করা যায়

vector<enumType> vEnums;

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


19

সি ++ 11 এর সাথে আসলে একটি বিকল্প রয়েছে: একটি সাধারণ টেম্প্লেটেটেড কাস্টম পুনরাবৃত্তকারী লেখা।

ধরে নেওয়া যাক আপনার এনাম হয়

enum class foo {
  one,
  two,
  three
};

এই জেনেরিক কোডটি কৌশলটি কার্যকর করবে - বেশ দক্ষতার সাথে - একটি জেনেরিক শিরোনামে রাখুন, এটি আপনাকে যে কোনও এনামের জন্য পুনরাবৃত্তি করতে হবে তার জন্য আপনাকে পরিবেশন করবে:

#include <type_traits>
template < typename C, C beginVal, C endVal>
class Iterator {
  typedef typename std::underlying_type<C>::type val_t;
  int val;
public:
  Iterator(const C & f) : val(static_cast<val_t>(f)) {}
  Iterator() : val(static_cast<val_t>(beginVal)) {}
  Iterator operator++() {
    ++val;
    return *this;
  }
  C operator*() { return static_cast<C>(val); }
  Iterator begin() { return *this; } //default ctor is good
  Iterator end() {
      static const Iterator endIter=++Iterator(endVal); // cache it
      return endIter;
  }
  bool operator!=(const Iterator& i) { return val != i.val; }
};

আপনার এটি বিশেষজ্ঞ করতে হবে

typedef Iterator<foo, foo::one, foo::three> fooIterator;

এবং তারপরে আপনি রেঞ্জ-ফর ব্যবহার করে পুনরাবৃত্তি করতে পারেন

for (foo i : fooIterator() ) { //notice the parentheses!
   do_stuff(i);
}

আপনার এনামে ফাঁক নেই এই ধারণাটি এখনও সত্য; এনাম মান সংরক্ষণ করার জন্য আসলে বিটের সংখ্যার কোনও ধারণা নেই (স্ট্যান্ডার্ড :: অন্তর্নিহিত_প্রকারকে ধন্যবাদ)


1
@ লেপ? আপনি আলাদা এনামের জন্য আলাদা আলাদা টাইপডিফ তৈরি করেন।
অ্যান্ড্রু লাজার

2
@lepe এ কথাটি বলার মতো যা std::vectorজেনেরিক নয় কারণ std::vector<foo>আবদ্ধ foo
কাইল স্ট্র্যান্ড 21

1
typedef Iterator<color, color::green, color::red> colorIterator;টেম্পলেট ইনস্ট্যান্টেশনগুলি কীভাবে কাজ করে তা আপনি নিশ্চিত হয়েছেন তা নিশ্চিত করুন।
অ্যান্ড্রু লাজার 17

2
ওহ, আমি সমস্যাটি দেখতে পাচ্ছি - foo operator*() { ...হওয়া উচিত C operator*() { ...
কাইল স্ট্র্যান্ড

1
@ কাইলস্ট্র্যান্ড: আপনি এটি পেয়েছেন! এটি এখন পুরোপুরি জ্ঞান করে তোলে। কোড আপডেট করা উচিত? আপনার ব্যাখ্যার জন্য সবাইকে ধন্যবাদ।
Lepe

16

এই সমাধানগুলি খুব জটিল, আমি এটি করি:

enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3};

const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary };

for (NodePosition pos : NodePositionVector) {
...
}

আমি কেন জানি এটিকে নিম্নমানের করা হয়েছিল। এটি একটি যুক্তিসঙ্গত সমাধান।
পল ব্রান্নান

11
আমি প্রত্যাশা করেছিলাম কারণ এন্ট্রি দুটি জায়গায় বজায় রাখা দরকার।
পিঁপড়া

সি ++ for (NodePosition pos : NodePositionVector)সিনট্যাক্সের অনুমতি দেয় ? আমি যতদূর জানি এটি জাভা বাক্য গঠন এবং আপনার সমতুল্য কিছু করার জন্য সি ++ এ পুনরাবৃত্তির প্রয়োজন।
thegreatjedi

3
@ থ্রেগ্রেজেজেদি যেহেতু সি ++ ১১ আপনি এটিকে আরও সহজতর করতে পারেন: (অটো পোস্ট: নোডপজিশন ভেক্টর) জন্য {..}
এনজোজ

@ থেগ্রেটেজেডি এই প্রশ্নটি জিজ্ঞাসা করার চেয়ে অনুসন্ধান বা তত্কালীন কোনও পরীক্ষা প্রোগ্রাম সংকলন করা তত দ্রুততর হত। তবে হ্যাঁ, সি ++ 11 সাল থেকে এটি পুরোপুরি বৈধ সি ++ সিনট্যাক্স, যা সংকলকটি সাধারণত পুনরাবৃত্তির মাধ্যমে সমতুল্য (এবং আরও বেশি ভার্বোজ / কম বিমূর্ত) কোডটিতে অনুবাদ করে; দেখতে cppreference । এবং, এনজোজ যেমন বলেছিলেন, সি ++ 11 আরও যুক্ত করেছে auto, সুতরাং আপনাকে (এ) কোনও রূপান্তর অপারেটর ব্যবহার করার প্রয়োজন না পড়লে বা (বি) autoকোনও কারণে পছন্দ না করলে আপনার উপাদানগুলির প্রকারটি স্পষ্টভাবে ঘোষণা করতে হবে না unless । বেশিরভাগ পরিসীমা forব্যবহারকারীরা autoAFAICT
আন্ডারস্কোর_১৫

9

আমি প্রায়শই এমন করি

    enum EMyEnum
    {
        E_First,
        E_Orange = E_First,
        E_Green,
        E_White,
        E_Blue,
        E_Last
    }

    for (EMyEnum i = E_First; i < E_Last; i = EMyEnum(i + 1))
    {}

বা যদি ধারাবাহিক না হয় তবে নিয়মিত পদক্ষেপ সহ (যেমন বিট পতাকা)

    enum EAnimalCaps
    {
        E_First,
        E_None    = E_First,
        E_CanFly  = 0x1,
        E_CanWalk = 0x2
        E_CanSwim = 0x4,
        E_Last
    }

    class MyAnimal
    {
       EAnimalCaps m_Caps;
    }

    class Frog
    {
        Frog() : 
            m_Caps(EAnimalCaps(E_CanWalk | E_CanSwim))
        {}
    }

    for (EAnimalCaps= E_First; i < E_Last; i = EAnimalCaps(i << 1))
    {}

তবে, মূল্য-বিট-প্রিন্টের মুদ্রণের ব্যবহার কী?
আনু

1
বিটমাস্ক তৈরি করতে এনাম ব্যবহার করতে। যেমন একক ভেরিয়েবলে বেশ কয়েকটি বিকল্প একত্রিত করুন, তারপরে প্রতিটি বিকল্পের জন্য পরীক্ষার জন্য ফর ব্যবহার করুন। আরও ভাল উদাহরণ সহ আমার পোস্ট স্থির।
নিকি

আমি এখনও এর ব্যবহার পেতে পারি না (এবং আপনার পোস্টটি এখনও পুরানো উদাহরণটি দেখায়)! বিটমাস্ক হিসাবে এনাম ব্যবহার করা সত্যিই সহায়ক, তবে বিন্দুগুলিকে সংযোগ করতে সক্ষম হয়নি! আপনি দয়া করে বিশদটি আপনার উদাহরণে কিছুটা বিশদভাবে বর্ণনা করতে পারেন, আপনি অতিরিক্ত কোডও রাখতে পারেন।
আনু

@ আনু দুঃখিত, আপনার মন্তব্যটি দেখেনি। বিটমাস্ক উদাহরণ হিসাবে ব্যাঙ শ্রেণি যোগ করা হয়েছে
Niki

8

আপনি একটি এনাম দিয়ে পারবেন না। হতে পারে একটি এনাম আপনার পরিস্থিতির জন্য সবচেয়ে উপযুক্ত নয়।

একটি সাধারণ কনভেনশন হ'ল সর্বশেষ এনাম মানটির নাম ম্যাক্সের মতো নামকরণ এবং এটি ব্যবহার করে কোনও লুপ নিয়ন্ত্রণ করতে to


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

6

এমন কিছু যা অন্যান্য উত্তর মধ্যে আবৃত করা হয় নি = আপনি আপনার ব্যবহার করতে পারবেন না শক্তিশালী ভাবে টাইপ সি ++ 11 enums ব্যবহার করছেন ++বা + intতাদের উপর। সেক্ষেত্রে, কিছুটা বার্তাবহ সমাধানের প্রয়োজন:

enum class myenumtype {
  MYENUM_FIRST,
  MYENUM_OTHER,
  MYENUM_LAST
}

for(myenumtype myenum = myenumtype::MYENUM_FIRST;
    myenum != myenumtype::MYENUM_LAST;
    myenum = static_cast<myenumtype>(static_cast<int>(myenum) + 1)) {

  do_whatever(myenum)

}

3
... তবে সি ++ 11 এর জন্য ভিত্তিক ব্যাপ্তিটি অন্য উত্তরগুলিতে দেখানো হয়েছে। :-)
ঋষি

5

আপনি নিম্নলিখিত ম্যাক্রোটি চেষ্টা ও সংজ্ঞায়িত করতে পারেন:

#define for_range(_type, _param, _A1, _B1) for (bool _ok = true; _ok;)\
for (_type _start = _A1, _finish = _B1; _ok;)\
    for (int _step = 2*(((int)_finish)>(int)_start)-1;_ok;)\
         for (_type _param = _start; _ok ; \
 (_param != _finish ? \
           _param = static_cast<_type>(((int)_param)+_step) : _ok = false))

এখন আপনি এটি ব্যবহার করতে পারেন:

enum Count { zero, one, two, three }; 

    for_range (Count, c, zero, three)
    {
        cout << "forward: " << c << endl;
    }

এটি স্বাক্ষরবিহীন, পূর্ণসংখ্যা, এনাম এবং চরগুলির মাধ্যমে পিছন এবং সম্মুখের দিকে পুনরাবৃত্তি করতে ব্যবহৃত হতে পারে:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}


for_range (char, c, 'z','a')
{
    cout << c << endl;
}

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

unsigned p[4][5];

for_range (Count, i, zero,three)
    for_range(unsigned int, j, 4, 0)
    {   
        p[i][j] = static_cast<unsigned>(i)+j;
    }

আপনি স্পষ্টতই গণ্যমানের মাধ্যমে পুনরাবৃত্তি করতে পারবেন না।


1
এটি একটি দুর্দান্ত হ্যাক! যদিও এটি সি ++ এর চেয়ে সি এর পক্ষে বেশি উপযুক্ত, কেউ বলতে পারেন।
einpoklum

3
_A1অনুমোদিত নাম নয়, এটি নিম্নলিখিত মূল অক্ষরের একটি শীর্ষস্থানীয় আন্ডারস্কোর।
মার্টিন উয়েডিং

3

আপনি আপনার অঙ্কিত প্রকারের জন্য বৃদ্ধি / হ্রাস অপারেটরগুলি ওভারলোড করতে পারেন।


1
আপনি সি বা সি ++ গণিত ধরণের কোনও অপারেটরকে ওভারলোড করতে পারবেন না। আপনি যদি না এমন একটি কাঠামো / শ্রেণি তৈরি করেন যা মানগুলির একটি গণনা অনুকরণ করে।
ট্রেভর হিকি

2
সি ++ এনমগুলিতে ওভারলোডিং অপারেটরদের অনুমতি দেয়। স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / 2571456/ … দেখুন ।
আর্চ ডি রবিসন

অতিরিক্ত বৃদ্ধি / হ্রাস ওভারলোডিং যখন অতিরিক্ত প্রবাহিত হয় তখন কী করা উচিত সে বিষয়ে সিদ্ধান্ত নেওয়া দরকার
এফোনামাস

3

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

enum Item { Man, Wolf, Goat, Cabbage }; // or enum class

for (auto item : {Wolf, Goat, Cabbage}) { // or Item::Wolf, ...
    // ...
}

এটি আমার মনে হয় একটি দুর্দান্ত বিকল্প। আমি অনুমান করছি এমন প্রশ্ন জিজ্ঞাসা করার সময় আমি যে জাতীয় সি ++ অনুচ্ছেদের চেয়ে বেশি ব্যবহার করেছি সেগুলি অবশ্যই হবে?
আদম

হ্যাঁ. এটি একটি স্ট্যান্ড :: পুনরুদ্ধারকারী_লিস্ট <আইটেম> এর মাধ্যমে পুনরাবৃত্তি করে। লিংক
মার্সকি

2

আপনি যদি চূড়ান্ত COUNT আইটেমটি দিয়ে এনামকে দূষিত করতে না চান (কারণ সম্ভবত আপনি যদি একটি স্যুইচে এনাম ব্যবহার করেন তবে সংকলক আপনাকে অনুপস্থিত কেস COUNT সম্পর্কে সতর্ক করবে) :) আপনি এটি করতে পারেন:

enum Colour {Red, Green, Blue};
const Colour LastColour = Blue;

Colour co(0);
while (true) {
  // do stuff with co
  // ...
  if (co == LastColour) break;
  co = Colour(co+1);
}

2

এখানে আরও একটি সমাধান রয়েছে যা কেবল সংঘবদ্ধ এনামগুলিতে কাজ করে। এটি ইনক্রিমেন্টে কদর্যতা ব্যতীত প্রত্যাশিত পুনরাবৃত্তি দেয় যা এটি যেখানে রয়েছে সেহেতু এটিই সি ++ তে কি ভাঙা।

enum Bar {
    One = 1,
    Two,
    Three,
    End_Bar // Marker for end of enum; 
};

for (Bar foo = One; foo < End_Bar; foo = Bar(foo + 1))
{
    // ...
}

1
বর্ধন সংক্ষিপ্ত করা যেতে পারে foo = Bar(foo + 1)
হলিব্ল্যাকট্যাগ

ধন্যবাদ, হলিব্ল্যাকগ্যাট, আমি আপনার দুর্দান্ত পরামর্শটি অন্তর্ভুক্ত করেছি! আমি আরও লক্ষ্য করেছি যে দাঙ্গার কাছে প্রায় একই সমাধান রয়েছে তবে শক্তিশালী টাইপিংয়ের সাথে সামঞ্জস্যপূর্ণ (এবং এইভাবে আরও ভার্বোস)।
ইথান ব্র্যাডফোর্ড

2
enum class A {
    a0=0, a3=3, a4=4
};
constexpr std::array<A, 3> ALL_A {A::a0, A::a3, A::a4}; // constexpr is important here

for(A a: ALL_A) {
  if(a==A::a0 || a==A::a4) std::cout << static_cast<int>(a);
}

একজন constexpr std::array সংকলক দ্বারা অ্যারে ইনস্ট্যান্ট করা ছাড়াই এমনকি অ-অনুক্রমিক এনামগুলিকেও পুনরাবৃত্তি করতে পারে। এটি সংকলকের অপ্টিমাইজেশন হিউরিস্টিক্স এবং আপনি অ্যারের ঠিকানা গ্রহণ করেন কিনা তা নির্ভর করে।

আমার পরীক্ষা-নিরীক্ষায়, আমি খুঁজে পেয়েছি যে g++9.1 -O3বিহীন উপরের অ্যারেটিকে অপ্টিমাইজ করবে যদি সেখানে 2 অ-অনুক্রমিক মান বা বেশ কয়েকটি ধারাবাহিক মান থাকে (আমি 6 পর্যন্ত পরীক্ষা করেছি)। তবে আপনার যদি কোনও ifবিবৃতি থাকে তবে এটি এটি করে । (আমি একটি বিবৃতি দিয়ে চেষ্টা করেছি যা ক্রমানুসারে অ্যারেতে সমস্ত উপাদানগুলির চেয়ে একটি পূর্ণসংখ্যার মানকে তুলনা করে এবং এটি কোনওটি বাদ না দেওয়া সত্ত্বেও পুনরাবৃত্তিকে ইনডিল করে, তবে আমি যদি বিবৃতিটি রেখে যাই, মানগুলি স্মৃতিতে রাখা হয়।) এটি 5 টিও ইনলাইন করে [একটি ক্ষেত্রে | একটি অ-অনুক্রমিক এনাম থেকে মানগুলি https://godbolt.org/z/XuGtoc] । আমার সন্দেহ হয় এই অদ্ভুত আচরণটি ক্যাশ এবং শাখার পূর্বাভাসের সাথে গভীর হিউরিস্টিক্সের কারণে।

এখানে গডবোল্টে একটি সাধারণ পরীক্ষার পুনরাবৃত্তির লিঙ্ক রয়েছে যা দেখায় যে অ্যারে সর্বদা তাত্ক্ষণিকভাবে আসে না।

এই কৌশলটির দাম এনাম উপাদানগুলি দুবার লিখছে এবং দুটি তালিকাকে সিঙ্কে রাখছে।


আমি সরল পরিসরের মতো-লুপ শব্দার্থবিজ্ঞান পছন্দ করি এবং আমি মনে করি এটি আরও বিবর্তিত হবে যার কারণে আমি এই সমাধানটি পছন্দ করি।
rtischer8277

2

বাজার্ন স্ট্রোস্ট্রপের সি ++ প্রোগ্রামিং ভাষার বইতে আপনি পড়তে পারেন যে তিনি operator++আপনার নির্দিষ্টটির জন্য ওভারলোডের প্রস্তাব দিচ্ছেন enumenumএই নির্দিষ্ট পরিস্থিতিতে ভাষাতে ব্যবহারকারী-সংজ্ঞায়িত প্রকার এবং ওভারলোডিং অপারেটর উপস্থিত রয়েছে।

আপনি নিম্নলিখিত কোড করতে সক্ষম হবেন:

#include <iostream>
enum class Colors{red, green, blue};
Colors& operator++(Colors &c, int)
{
     switch(c)
     {
           case Colors::red:
               return c=Colors::green;
           case Colors::green:
               return c=Colors::blue;
           case Colors::blue:
               return c=Colors::red; // managing overflow
           default:
               throw std::exception(); // or do anything else to manage the error...
     }
}

int main()
{
    Colors c = Colors::red;
    // casting in int just for convenience of output. 
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    return 0;
}

পরীক্ষার কোড: http://cpp.sh/357gb

মনে হয় যে আমি ব্যবহার করছি enum class। কোড enumএছাড়াও ভাল কাজ করে । তবে আমি পছন্দ করি enum classযেহেতু সেগুলি শক্ত টাইপযুক্ত এবং সংকলনের সময় আমাদের ভুল করতে বাধা দিতে পারে।


এই পোস্টে একটি ডাউনভোট দেওয়া হয়েছিল। কোনও কারণেই কেন এটি প্রশ্নের উত্তর দেবে না?
LAL

কারণ সম্ভবত এটি আর্কিটেকচারালি ভাষায় বলা একটি ভয়াবহ সমাধান: এটি আপনাকে গ্লোবাল-ভিত্তিক-যুক্তি যুক্ত একটি নির্দিষ্ট উপাদানকে আবদ্ধ করে (আপনার গণনা) লিখতে বাধ্য করে, তদুপরি, যদি আপনার গণনা যে কোনও কারণে পরিবর্তিত হয় তবে আপনি আপনার + সম্পাদনা করতে বাধ্য হয়েছেন + অপারেটরও, কোনও দৃষ্টিভঙ্গি হিসাবে এটি কোনও মাঝারি-বৃহত প্রকল্পের পক্ষে টেকসই নয়, এটি কোনও বিস্ময়ের বিষয় নয় যে এটি
বার্জন স্ট্রোস্ট্রপের

মূল প্রশ্নটি হ'ল অপারেটরটি সম্পর্কে enum। এটি কোনও স্থাপত্যের প্রশ্ন ছিল না। আমি বিশ্বাস করি না যে ২০১৩ সালে সি ++ একটি বিজ্ঞান কল্পকাহিনী ছিল।
এলএল

1

এমএস সংকলকগুলির জন্য:

#define inc_enum(i) ((decltype(i)) ((int)i + 1))

enum enumtype { one, two, three, count};
for(enumtype i = one; i < count; i = inc_enum(i))
{ 
    dostuff(i); 
}

দ্রষ্টব্য: এটি সাধারণ টেমপ্ল্লেটেড কাস্টম পুনরাবৃত্ত উত্তরের চেয়ে অনেক কম কোড।

আপনি এটির typeofপরিবর্তে ব্যবহার করে জিসিসির সাথে কাজ করতে পারেন decltype, তবে এটি সংকলন করে তা নিশ্চিত করার জন্য আমার কাছে এই মুহূর্তে সেই সংকলকটি হাতে নেই।


এটি decltypeস্ট্যান্ডার্ড সি ++ হয়ে যাওয়ার 5 বছর পরে লেখা হয়েছিল , সুতরাং আপনার typeofপ্রাচীন জিসিসি থেকে পুরানো প্রস্তাব দেওয়া উচিত নয় । প্রায় সাম্প্রতিক জিসিসি decltypeঠিক ঠিক পরিচালনা করে । অন্যান্য সমস্যা রয়েছে: সি-স্টাইলের কাস্টগুলি নিরুৎসাহিত করা হচ্ছে, এবং আরও ম্যাক্রো। যথাযথ সি ++ বৈশিষ্ট্যগুলি একই জেনেরিক কার্যকারিতা দিতে পারে। এই ভাল ব্যবহার করতে পুনর্লিখিত করা হবে static_cast& একটি টেমপ্লেট ফাংশন: template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }। এবং অ-জন্য ক্যাসেটের প্রয়োজন হয় না enum class। অন্যথা, অপারেটার প্রতি ওভারলোড করা যাবে enumপ্রকার (তিল)
underscore_d

1
typedef enum{
    first = 2,
    second = 6,
    third = 17
}MyEnum;

static const int enumItems[] = {
    first,
    second,
    third
}

static const int EnumLength = sizeof(enumItems) / sizeof(int);

for(int i = 0; i < EnumLength; i++){
    //Do something with enumItems[i]
}

এই সমাধানটি স্মৃতিতে অপ্রয়োজনীয় স্ট্যাটিক ভেরিয়েবল তৈরি করবে যখন
এনামের

না বদলে constexpr static const int enumItems[]
মোহাম্মদ কানন

0

সি ++ এর আত্মপরিচয় নেই, তাই রান-টাইমে আপনি এই ধরণের জিনিস নির্ধারণ করতে পারবেন না।


1
আপনি কি আমাকে ব্যাখ্যা করতে পারেন কেন একটি এনামের মাধ্যমে পুনরুক্তি করতে "অন্তর্মুখ" প্রয়োজন হবে?
জোনাথন মে

শব্দটি প্রতিচ্ছবি হতে পারে ?
kͩeͣmͮpͥ ͩ

2
আমি 2 টি কথা বলার চেষ্টা করছি: 1) অন্যান্য অনেক উত্তর অনুসারে সি ++ এটি সম্পাদন করতে পারে তাই আপনি যদি এটি বলতে না পারেন তবে একটি লিঙ্ক বা আরও স্পষ্টকরণ প্রয়োজন। 2) এটির বর্তমান ফর্মে এটি সেরা মন্তব্য, অবশ্যই কোনও উত্তর নয়।
জনাথন মে

আমার উত্তরটি তখনই
কমিয়ে

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

0

যদি আপনি জানতেন যে এনাম মানগুলি ক্রমযুক্ত ছিল, উদাহরণস্বরূপ Qt: কী এনাম, আপনি এটি করতে পারেন:

Qt::Key shortcut_key = Qt::Key_0;
for (int idx = 0; etc...) {
    ....
    if (shortcut_key <= Qt::Key_9) {
        fileMenu->addAction("abc", this, SLOT(onNewTab()),
                            QKeySequence(Qt::CTRL + shortcut_key));
        shortcut_key = (Qt::Key) (shortcut_key + 1);
    }
}

এটি প্রত্যাশার মতো কাজ করে।


-1

কেবল ইনটের একটি অ্যারে তৈরি করুন এবং অ্যারের উপরে লুপ করুন, তবে শেষ উপাদানটি -1 বলুন এবং এটিকে প্রস্থান শর্তের জন্য ব্যবহার করুন।

যদি এনাম হয়:

enum MyEnumType{Hay=12,Grass=42,Beer=39};

তারপরে অ্যারে তৈরি করুন:

int Array[] = {Hay,Grass,Beer,-1};

for (int h = 0; Array[h] != -1; h++){
  doStuff( (MyEnumType) Array[h] );
}

এটি যতক্ষণ না -1 চেক অবশ্যই কোনও উপাদানগুলির সাথে সংঘর্ষ না করে ততক্ষণ উপস্থাপনের ইনটগুলি ভেঙ্গে যায় না।

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