2010-03-19 15 views
9

यह कितना भयानक है - या यह पूरी तरह से स्वीकार्य है - एक गणना पर एक लूप को अनुक्रमणित करने के लिए?गणना मूल्यों पर लूप

मेरे पास एक गणना परिभाषित है। अक्षर के मान डिफ़ॉल्ट मान हैं। निर्दिष्ट मूल्यों का कोई महत्व नहीं है, इसका कोई महत्व नहीं होगा, और भविष्य में जोड़े गए किसी भी अक्षर के मूल्यों का कोई महत्व नहीं होगा। यह केवल अनुमत मानों को सीमित करने और चीजों को आसान बनाने के लिए परिभाषित किया गया है। इसलिए मान हमेशा 0 पर शुरू और से 1.

मैं एक पाश की तरह तो सेट कर सकता हूँ में वृद्धि होगी:

enum MyEnum 
{ 
    value1, 
    value2, 
    value3, 
    maxValue 
} 

for(MyEnum i = value1; i < maxValue; i = static_cast<MyEnum>(i+1)){} 
+1

स्टॉप! आप पास्कल के लिए मुझे नास्तिक बना रहे हैं। –

उत्तर

4

जहां तक ​​मेरा सवाल है, कि बस ठीक है। मुझे यकीन है कि वहां कुछ शुद्धवादी कहीं बाहर निकल जाएंगे, लेकिन जहां तक ​​भाषा की कल्पना का सवाल है, वह कोड सही तरीके से काम करेगा, इसलिए यदि आप अपने जीवन को आसान बनाते हैं तो आपको इसके लिए जाने के लिए स्वतंत्र महसूस होना चाहिए।

0

यह तब तक ठीक है जब तक आप विशेष रूप से एनम मूल्य का मूल्य निर्धारित नहीं करते हैं। आपका उदाहरण ठीक है, लेकिन यह बुरा हो सकता है: 7.2/1 में

// this would be bad 
enum MyEnum 
{ 
    value1, 
    value2 = 2, 
    value3, 
    maxValue 
}; 

मानक राज्यों के रूप में:

एक प्रारंभकर्ता बिना एक प्रगणक परिभाषा प्रगणक मूल्य में वृद्धि से प्राप्त देता है एक के पिछले गणनाकर्ता का मान।

+2

यही कारण है कि मैंने निर्दिष्ट किया कि शाब्दिक के मूल्य महत्वपूर्ण नहीं हैं और कभी नहीं होंगे। उन्हें डिफ़ॉल्ट मान मिलते हैं। – Rachel

+1

@ राहेल - मैं बस गलत होने के बारे में स्पष्ट होने की कोशिश कर रहा था। जैसा कि मैंने कहा था कि मैं अपने उत्तर की पहली वाक्य है, यह वही है जो आप इसे करते हैं। –

0

मुझे इसका कोई विशिष्ट उपयोग नहीं पता है जो वास्तव में उपयोगी है और मुझे लगता है कि खराब कोड है। क्या होगा अगर कोई इस तरह की चीजों को कई पुस्तकालयों में देखा गया हो?

enum MyEnum 
{ 
    value1, 
    value2, 
    value3, 
    maxValue = 99999; 
}; 
+0

फिर वे दुर्भावनापूर्ण रूप से मेरे कोड को तोड़ देंगे। – Rachel

+0

आईएमओ, enum को एक टिप्पणी जोड़ने का एक अच्छा कारण है - उन्हें बताओ नहीं। – Steve314

2

ऐसा करने में मददगार हो सकता है।

enum MyEnum 
{ 
    first, 
    value1, 
    value2, 
    value3, 
    last 
} 
+1

जो "पहला" अपना अनूठा मूल्य देता है। सामान्य लूप मुहावरे आधे खुले होते हैं - अंत में अनन्य और अंत में अनन्य। मैं enum के अंत में "first = value1" का उपयोग करने का सुझाव देता हूं, या बस "value1" को फिर से नामित करने का सुझाव देता हूं जो इसे स्पष्ट करता है और हमेशा पहला होगा। – Steve314

0

इसलिए मान हमेशा 0 और वृद्धि पर से 1.

शुरू कर देंगे ध्यान रखें जब तक कि इस कोडिंग मानक जहां काम करते हैं, में लिखा है एक रखरखाव प्रोग्रामर आता है जब कि 6 महीनों में साथ और की तरह एक गणना करने के लिए कोई परिवर्तन नहीं करता:

enum MyEnum 
{ 
    value1, 
    value2 = 5, 
    value3, 
    maxValue 
} 
क्योंकि एक नया आवश्यकता के

, आप को समझाने के लिए मिल जाएगा उनके वैध परिवर्तन ने आवेदन क्यों तोड़ दिया।

नाम करने के लिए मूल्यों को संलग्न करने के लिए आप एक नक्शा इस्तेमाल कर सकते हैं:

int values[] = { 0, 1, 2 }; 
int valuesSize = sizeof(values)/sizeof(values[0]); 

for (int i = 0; i < valuesSize; ++i) 
{ 
    func(values[i]); 
} 

या एक तुलनीय विधि का उपयोग कर:

typedef std::map<std::string,int> ValueMap; 
ValueMap myMap; 
myMap.insert(make_pair("value1", 0)); 
myMap.insert(make_pair("value2", 1)); 
myMap.insert(make_pair("value3", 2)); 

for(ValueMap::iterator iter = theMap.begin(); iter != theMap.end(); ++iter) 
{ 
    func(iter->second); 
} 

नाम आप एक सी शैली सरणी इस्तेमाल कर सकते हैं कोई फर्क नहीं है, तो एक std :: वेक्टर।

इसके अलावा, आप क्या कहते हैं अगर सच है, और the values will always start at 0 and increase by 1 तो मैं क्यों यह काम नहीं होगा करने के लिए के रूप में उलझन में हूँ:

const int categoryStartValue = 0; 
const int categoryEndValue = 4; 

for (int i = categoryStartValue; i < categoryEndValue; ++i) 
{ 
    func(i); 
} 
-1

आप एक स्विच बयान गैर खिलाफ की रक्षा के साथ पाश शरीर लपेट सकता है - मूल्यवान मूल्य। यह संभवतः सुपर धीमी है, जैसा कि maxValue = 99 99 में है; मामला, लेकिन यह कभी भी सबसे बुरी बात नहीं हो सकती है। मैं अपने कोड अड्डों में इस शैली यहां हर समय देखना

enum MyEnum { 
value1, 
value2, 
value3, 
maxValue 
} 
for(MyEnum i = value1; i < maxValue; i = static_cast<MyEnum>(i+1)){ 
    switch(i) 
    { 
     case value1: 
     case value2: 
     case value3: 
        //actual code 
    } 

} 
+0

अहह! डरावना फॉर/केस पैटर्न! http://thedailywtf.com/Articles/The_FOR-CASE_paradigm.aspx http://thedailywtf.com/Articles/Switched_on_Loops.aspx –

0

यह आसान नहीं ...

एकमात्र समाधान मैंने कभी पाया वास्तव में enum पर एक वर्ग को लागू करें, और तब मैक्रो का उपयोग करने के लिए था enum परिभाषित करने के लिए ...

DEFINE_NEW_ENUM(MyEnum, (value1)(value2)(value3)) 

मूल विचार एक एसटीएल कंटेनर, MyEnum प्रतीक के आधार पर एक टेम्पलेट वर्ग में स्थिर संग्रहीत में मान संग्रहीत करने के लिए है। इस तरह आप पूरी तरह से परिभाषित पुनरावृत्ति प्राप्त करते हैं, और आपको शून्य के लिए एक अमान्य स्थिति भी मिलती है (end() की वजह से)।

मैं प्रयोग किया जाता एक हल कर pair<Enum,std::string> की vector ताकि मैं लॉग में सुंदर छपाई और लंबे समय तक चलने क्रमबद्धता से फायदा हो सकता है (और यह डेटा के छोटे सेट के लिए एक साहचर्य कंटेनर से अधिक तेज़ है और कम स्मृति लेता है क्योंकि)।

मुझे अभी तक कोई बेहतर तरीका नहीं मिला है, क्या सी ++ 11 अंततः enums पर पुनरावृत्ति प्राप्त करता है या नहीं?

8

मैं इन मामलों

enum Foo { 
A, B, C, Last 
}; 

typedef litb::enum_iterator<Foo, A, Last> FooIterator; 

int main() { 
    FooIterator b(A), e; 
    std::cout << std::distance(b, e) << " values:" << std::endl; 
    std::copy(b, e, std::ostream_iterator<Foo>(std::cout, "\n")); 

    while(b != e) doIt(*b++); 
} 

के लिए कुछ समय पहले एक enum इटरेटर लिखा आप रुचि रखते हैं, यहाँ कोड है। यदि आप चाहें, तो आप +, <, [] और दोस्तों को प्रदान करके इसे यादृच्छिक एक्सेस इटेटरेटर के रूप में विस्तारित कर सकते हैं। std::distance जैसे एल्गोरिदम, फिर यादृच्छिक-पहुंच पुनरावर्तक के लिए O(1) समय जटिलता प्रदान करके आपको धन्यवाद देंगे।

#include <cassert> 

namespace litb { 

template<typename Enum, Enum Begin, Enum End> 
struct enum_iterator 
    : std::iterator<std::bidirectional_iterator_tag, Enum> { 
    enum_iterator():c(End) { } 
    enum_iterator(Enum c):c(c) { } 

    enum_iterator &operator=(Enum c) { 
    this->assign(c); 
    return *this; 
    } 

    enum_iterator &operator++() { 
    this->inc(); 
    return *this; 
    } 

    enum_iterator operator++(int) { 
    enum_iterator cpy(*this); 
    this->inc(); 
    return cpy; 
    } 

    enum_iterator &operator--() { 
    this->dec(); 
    return *this; 
    } 

    enum_iterator operator--(int) { 
    enum_iterator cpy(*this); 
    this->dec(); 
    return cpy; 
    } 

    Enum operator*() const { 
    assert(c != End && "not dereferencable!"); 
    return c; 
    } 

    bool equals(enum_iterator other) const { 
    return other.c == c; 
    } 

private: 
    void assign(Enum c) { 
    assert(c >= Begin && c <= End); 
    this->c = c; 
    } 

    void inc() { 
    assert(c != End && "incrementing past end"); 
    c = static_cast<Enum>(c + 1); 
    } 

    void dec() { 
    assert(c != Begin && "decrementing beyond begin"); 
    c = static_cast<Enum>(c - 1); 
    } 

private: 
    Enum c; 
}; 

template<typename Enum, Enum Begin, Enum End> 
bool operator==(enum_iterator<Enum, Begin, End> e1, enum_iterator<Enum, Begin, End> e2) { 
    return e1.equals(e2); 
} 

template<typename Enum, Enum Begin, Enum End> 
bool operator!=(enum_iterator<Enum, Begin, End> e1, enum_iterator<Enum, Begin, End> e2) { 
    return !(e1 == e2); 
} 

} // litb 
+0

वह चालाक है। :) बस अपने हस्ताक्षर के लिए कहीं वहां अल्पविराम ऑपरेटर फेंकना होगा। – GManNickG

+0

क्यों 'ऑपरेटर == 'लेकिन कोई' ऑपरेटर>' (और दोस्तों) क्यों? –

+0

@ क्रिस मुझे इसकी आवश्यकता नहीं थी क्योंकि मेरा लक्ष्य सीमा का पुनरावृत्ति था, इसलिए मैं बिडरेक्शनल-इटरेटर इंटरफेस को लागू करने गया। लेकिन एक 'op>' निश्चित रूप से इस enum iterator के लिए समझ में आता है। –

0

मैं आमतौर पर शुरू और मेरे enums में अंत मान जब मैं यात्रा की जरूरत है, की तरह एक विशेष सिंटेक्स के साथ परिभाषित निम्नलिखित (स्पष्ट करने के लिए Doxygen शैली टिप्पणी के साथ):

enum FooType { 
    FT__BEGIN = 0,  ///< iteration sentinel 
    FT_BAR = FT__BEGIN, ///< yarr! 
    FT_BAZ,    ///< later, when the buzz hits 
    FT_BEEP,    ///< makes things go beep 
    FT_BOOP,    ///< makes things go boop 
    FT__END    ///< iteration sentinel 
} 

FT_ वहाँ मदद करने के लिए है नेमस्पेसिंग के साथ (enums के बीच संघर्ष से बचने के लिए) और डबल अंडरस्कोर वास्तविक मूल्यों और पुनरावृत्ति प्रेषणों के बीच अंतर करने में मदद करते हैं।

Sidenote:

इस लेखन मैं डबल अंडरस्कोर के बारे में चिंता (यह कार्यान्वयन सुरक्षित, IIRC?) उपयोगकर्ता पहचानकर्ता के लिए अनुमति नहीं किया जा रहा शुरू करते हैं, लेकिन मैं अभी तक एक समस्या हिट करने के लिए कर रहा हूँ (5-6 के बाद इस शैली में कोडिंग के वर्षों)। यह ठीक हो सकता है क्योंकि प्रदूषण से बचने और वैश्विक नामस्थान में हस्तक्षेप करने के लिए मैं हमेशा अपने सभी प्रकारों को नामस्थान में डालता हूं।

संबंधित मुद्दे