सतत enum C ++ 11


17

क्या सी ++ 11 में जांच करने का एक तरीका है यदि एक एनम निरंतर है ?

यह एक एनम मान देने के लिए पूरी तरह से वैध है जो नहीं हैं। क्या सी + 14, सी ++ 17 या शायद सी ++ 20 की जांच करने के लिए एक प्रकार की विशेषता है जैसे कि एनम निरंतर है? इसका उपयोग static_assert में किया जाना है।

एक छोटा सा उदाहरण इस प्रकार है:

enum class Types_Discontinuous {
  A = 10,
  B = 1,
  C = 100
};

enum class Types_Continuous {
  A = 0,
  B = 1,
  C = 2
};

static_assert(SOME_TEST<Types_Discontinuous>::value, "Enum should be continuous"); // Fails
static_assert(SOME_TEST<Types_Continuous>::value, "Enum should be continuous");    // Passes

1
मीन्स जारी है, कि इसमें आरोही क्रम है या इसका मतलब है कि हर मूल्य के लिए शून्य और फिर +1 से शुरू होता है?
RoQuotriX

5
एन्यूमरेशन लेबल्स को एन्यूमरेट करने का कोई तरीका नहीं है इसलिए इसे प्रोग्राम के अंदर से करना संभव नहीं है।
कुछ प्रोग्रामर

1
दिलचस्प। मैं टेम्पलेट प्रोग्रामिंग की तर्ज पर सोच रहा हूँ कि कैसे आप एक फैक्टर की गणना कर सकते हैं। आप इस चीज़ को दो सीमा A और C से जोड़ देंगे, और टेम्पलेट फ़ंक्शंस SFINAE के माध्यम से उपस्थिति या अन्यथा उनके बीच के सभी मानों की जाँच करेंगे enum। अफसोस की बात है कि मेरे पास एक दिन का काम है, इसलिए मैं इसे लिखने का प्रयास नहीं कर सकता, हालांकि मैं इस दृष्टिकोण के आधार पर एक उत्तर दूंगा। मुझे पूरा यकीन है कि @barry या @sehe जैसा कोई भी ऐसा कर सकता है।
स्नानागार

1
@RoQuOTriX आप किसी लेबल के मान से कैसे मिलान करेंगे? और आप लेबल के क्रम की जांच कैसे करेंगे? और यह संकलन-समय पर कैसे किया जा सकता है (जिसकी आवश्यकता है static_assert)? यहां तक ​​कि अगर आप एक "सुंदर समाधान" नहीं बना सकते हैं, तो कृपया किसी भी तरह से उत्तर लिखें क्योंकि मैं बहुत उत्सुक हूं कि यह सामान्य तरीके से कैसे किया जा सकता है।
कुछ प्रोग्रामर

1
@Someprogrammerdude आपने जो वर्णन किया वह "सुंदर" या अच्छा समाधान है। मेरा मतलब था "आसान" चेक समाधान, जिसे आपको हर एनम और ईश्वर के आशीर्वाद के लिए फिर से लिखना होगा, मुझे आशा है कि कोई भी ऐसा नहीं करता है
RoQuotriX

जवाबों:


7

के एक नंबर के लिए enumरों आप शायद का उपयोग कर इस माध्यम से अपने तरीके से हैक कर सकते हैं जादू Enum पुस्तकालय। उदाहरण के लिए:

#include "magic_enum.hpp"

template <typename Enum>
constexpr bool is_continuous(Enum = Enum{}) {
    // make sure we're actually testing an enum
    if constexpr (!std::is_enum_v<Enum>)
        return false;
    else {
        // get a sorted list of values in the enum
        const auto values = magic_enum::enum_values<Enum>();
        if (std::size(values) == 0)
            return true;

        // for every value, either it's the same as the last one or it's one larger
        auto prev = values[0];
        for (auto x : values) {
            auto next = static_cast<Enum>(magic_enum::enum_integer(prev) + 1);
            if (x != prev && x != next)
                return false;
            else
                prev = x;
        }
        return true;
    }
}

ध्यान दें कि यह वास्तव में है, जैसा कि पुस्तकालय का नाम है, "जादू" - पुस्तकालय कई संकलक-विशिष्ट हैक्स पर कार्य करता है। जैसा कि यह वास्तव में "शुद्ध सी ++" की आपकी आवश्यकता को पूरा नहीं करता है, लेकिन शायद उतना ही अच्छा है जितना हम तब तक प्राप्त कर सकते हैं जब तक कि हमारे पास भाषा में प्रतिबिंब सुविधाएं न हों।


यह वास्तव में जादू है लेकिन इससे मेरी स्थिति सबसे अच्छी होगी।
बार्ट

7

यह शुद्ध C ++ में संभव नहीं है, क्योंकि एनम वैल्यूज़ को एनुमरेट करने का कोई तरीका नहीं है, या मानों की संख्या और न्यूनतम और अधिकतम मानों की खोज करना है। लेकिन आप अपने कंपाइलर की मदद से कोशिश कर सकते हैं कि आप जो चाहते हैं उसके करीब कुछ लागू कर सकें। उदाहरण के लिए, gcc में एक संकलन त्रुटि को लागू करना संभव है यदि कोई switchकथन किसी एनम के सभी मानों को नहीं संभालता है:

enum class my_enum {
    A = 0,
    B = 1,
    C = 2
};

#pragma GCC diagnostic push
#if __GNUC__ < 5
#pragma GCC diagnostic error "-Wswitch"
#else
#pragma GCC diagnostic error "-Wswitch-enum"
#endif

constexpr bool is_my_enum_continuous(my_enum t = my_enum())
{
    // Check that we know all enum values. Effectively works as a static assert.
    switch (t)
    {
    // Intentionally no default case.
    // The compiler will give an error if not all enum values are listed below.
    case my_enum::A:
    case my_enum::B:
    case my_enum::C:
        break;
    }

    // Check that the enum is continuous
    auto [min, max] = std::minmax({my_enum::A, my_enum::B, my_enum::C});
    return static_cast< int >(min) == 0 && static_cast< int >(max) == 2;
}

#pragma GCC diagnostic pop

जाहिर है, यह किसी दिए गए एनम के लिए विशेष है, लेकिन ऐसे कार्यों की परिभाषा प्रीप्रोसेसर के साथ स्वचालित हो सकती है।


अगर मैं सही ढंग से समझूं तो अभी भी स्विच और मिनमैक्स के लिए सूची में सभी एनम मूल्यों को लिखने की आवश्यकता होगी। वर्तमान में मेरे पास कई एनम हैं इसलिए यह वास्तव में संभव है लेकिन मेरी स्थिति के लिए पसंद नहीं है।
बार्ट

1

मुझे इस पर जवाब देखना अच्छा लगेगा। मुझे इसकी आवश्यकता है।

दुर्भाग्य से, मुझे नहीं लगता कि मौजूदा उपयोगिताओं का उपयोग करना संभव है। यदि आप इस पर एक प्रकार की विशेषता को लागू करना चाहते हैं, तो आपको अपने संकलक से समर्थन की आवश्यकता है, इसलिए इसके लिए टेम्पलेट लिखना संभव नहीं है।

मैंने पहले से ही एक विशिष्ट टैग के साथ गणना को बढ़ाया है यह इंगित करने के लिए कि यह सन्निहित है और तुरंत आपको आकार देता है: enum class constructor c ++, विशिष्ट मान कैसे पास करें?

वैकल्पिक रूप से, आप अपनी खुद की विशेषता लिख ​​सकते हैं:

 template<T> struct IsContiguous : std::false_type {};

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


1
आप एक कोड चेकर लिख सकते हैं, जो संकलित करते समय जांचता है, यदि प्रकार सही है
RoQuotriX

हाँ सचमुच। यदि आप इसे लिखने की क्षमता रखते हैं।
JVApen

1

सभी एनुम निरंतर हैं। 0 हमेशा की अनुमति है; उच्चतम मूल्य की अनुमति दी गई उच्चतम एन्यूमरेटर अगले 1<<N -1(सभी बिट्स एक) तक है, और बीच में सभी मान भी अनुमत हैं। ((dcl.enum] 9.7.1 / 5)। यदि नकारात्मक एन्यूमरेटर्स को परिभाषित किया गया है, तो अनुमति दी गई निम्नतम मूल्य को समान रूप से निम्नतम एन्यूमरेटर को गोल करके परिभाषित किया गया है।

परिभाषित किए गए प्रगणक enumनिरंतर भाव में रेंज और सही प्रकार के मान के साथ हैं, लेकिन आप अतिरिक्त स्थिरांक को परिभाषित कर सकते हैं enumजिसमें समान गुण हैं:

constexpr enum class Types_Discontinuous = static_cast<Types_Discontinuous>(2)


2
यद्यपि आप सही हैं, यह ओपी से स्पष्ट है कि हम इसे परिभाषित मूल्यों के लिए जानना चाहते हैं। (पुनश्च: नीचे वोट मेरा नहीं है)
JVApen

1
@JVApen: यह सटीक समस्या है। "परिभाषित मूल्य" स्वयं एनम प्रकार की संपत्ति नहीं हैं। मानक स्पष्ट है कि एनम के मान क्या हैं।
एमएसएल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.