क्या एनम वर्ग को अंतर्निहित प्रकार में परिवर्तित किया जा सकता है?


112

क्या किसी enum classक्षेत्र को अंतर्निहित प्रकार में बदलने का कोई तरीका है ? मैंने सोचा था कि यह स्वचालित होगा, लेकिन स्पष्ट रूप से नहीं।

enum class my_fields : unsigned { field = 1 };

unsigned a = my_fields::field;

उस असाइनमेंट को GCC द्वारा खारिज किया जा रहा है। error: cannot convert 'my_fields' to 'unsigned int' in assignment


4
यदि आप अंतर्निहित प्रकार में परिवर्तित करना चाहते हैं तो उपयोग करें enum
पबि

1
FYI करें, इस नियम में परिभाषित किया गया है [C++11: 7.2/9]
ऑर्बिट

5
@Pubby अफसोस की बात है कि 'एनम' सभी एन्यूमरेंट्स के साथ बाहरी दायरे को प्रदूषित करता है। काश वहाँ दोनों दुनिया का कोई सबसे अच्छा नहीं है (वैसे भी C ++ 14 के रूप में) जो साफ़-सुथरा घोंसला बनाता है, जबकि अंतर्निहित रूप से आधार प्रकार में परिवर्तित होता है (जो कि सी + + अन्य वर्ग वंशानुक्रम को कैसे संभालता है, जब आप अधिक व्युत्पन्न प्रकार से गुजरते हैं। आधार प्रकार लेते हुए किसी फ़ंक्शन का मान या संदर्भ)।
ड्वेन रॉबिन्सन

2
@DwayneRobinson हाँ वहाँ है। एक अज्ञात या अधिक अधिमानतः एक नाम स्थान के अंदर एक अनकही एनम छड़ी। इस प्रकार यह स्कोप किया गया है और अभी भी अंतर्निहित अंतर रूपांतरण है। (हालांकि मुझे दो बार सोचना ज़रूरी है कि आपको इंट में बदलने की आवश्यकता क्यों है और शायद इस पर विचार करें कि क्या कोई बेहतर तरीका है।)
चरण 12

जवाबों:


178

मुझे लगता है कि आप अंतर्निहित प्रकार जानने के लिए std :: inher_type का उपयोग कर सकते हैं , और फिर कलाकारों का उपयोग कर सकते हैं:

#include <type_traits> //for std::underlying_type

typedef std::underlying_type<my_fields>::type utype;

utype a = static_cast<utype>(my_fields::field);

इस के साथ, आप की जरूरत नहीं है मान लेते हैं , अंतर्निहित प्रकार या आप की जरूरत नहीं है की परिभाषा में यह उल्लेख करने के लिए enum classकी तरह enum class my_fields : int { .... }या तो।

तुम भी एक लिख सकते हैं सामान्य परिवर्तित समारोह है कि परिवर्तित करने के लिए सक्षम होना चाहिए किसी भी enum class उसके अंतर्निहित करने के लिए अभिन्न प्रकार:

template<typename E>
constexpr auto to_integral(E e) -> typename std::underlying_type<E>::type 
{
   return static_cast<typename std::underlying_type<E>::type>(e);
}

फिर इसका उपयोग करें:

auto value = to_integral(my_fields::field);

auto redValue = to_integral(Color::Red);//where Color is an enum class!

और चूंकि फ़ंक्शन को घोषित किया जाता है constexpr, आप इसका उपयोग कर सकते हैं जहां निरंतर अभिव्यक्ति की आवश्यकता होती है:

int a[to_integral(my_fields::field)]; //declaring an array

std::array<int, to_integral(my_fields::field)> b; //better!

अब जब हम भविष्य में हैं:template <typename T> auto to_integral(T e) { return static_cast<std::underlying_type_t<T>>(e); }
रयान हेनिंग

1
@RHHaining: धन्यवाद। (बीटीडब्ल्यू, आपके पास constexprभविष्य में भी है, वास्तव में 2013 में मेरे पास जो था उससे कहीं अधिक शक्तिशाली: पी)
नवाज़

41

आप इसे नहीं बदल सकते परोक्ष , लेकिन कोई स्पष्ट डाली संभव है:

enum class my_fields : unsigned { field = 1 };

// ...

unsigned x = my_fields::field; // ERROR!
unsigned x = static_cast<unsigned>(my_fields::field); // OK

इस तथ्य पर भी ध्यान दें, कि अर्धविराम आपकी ईमम की परिभाषा में बंद घुंघराले ब्रेस के बाद होना चाहिए , न कि पहले।


0

underlying_castजब एनम मूल्यों को सही ढंग से क्रमबद्ध करने के लिए मुझे निम्न फ़ंक्शन उपयोगी लगता है।

namespace util
{

namespace detail
{
    template <typename E>
    using UnderlyingType = typename std::underlying_type<E>::type;

    template <typename E>
    using EnumTypesOnly = typename std::enable_if<std::is_enum<E>::value, E>::type;

}   // namespace util.detail


template <typename E, typename = detail::EnumTypesOnly<E>>
constexpr detail::UnderlyingType<E> underlying_cast(E e) {
    return static_cast<detail::UnderlyingType<E>>(e);
}

}   // namespace util

enum SomeEnum : uint16_t { A, B };

void write(SomeEnum /*e*/) {
    std::cout << "SomeEnum!\n";
}

void write(uint16_t /*v*/) {
    std::cout << "uint16_t!\n";
}

int main(int argc, char* argv[]) {
    SomeEnum e = B;
    write(util::underlying_cast(e));
    return 0;
}

0

जैसा कि अन्य लोगों ने बताया है कि कोई अंतर्निहित कास्ट नहीं है, लेकिन आप एक स्पष्ट उपयोग कर सकते हैं static_cast। मैं अपने कोड में निम्नलिखित हेल्पर फ़ंक्शन का उपयोग करता हूं ताकि एनम प्रकार और उसके अंतर्निहित वर्ग से परिवर्तित किया जा सके।

    template<typename EnumType>
    constexpr inline decltype(auto) getIntegralEnumValue(EnumType enumValue)
    {
        static_assert(std::is_enum<EnumType>::value,"Enum type required");
        using EnumValueType = std::underlying_type_t<EnumType>;
        return static_cast<EnumValueType>(enumValue);
    }

    template<typename EnumType,typename IntegralType>
    constexpr inline EnumType toEnum(IntegralType value)
    {
        static_assert(std::is_enum<EnumType>::value,"Enum type required");
        static_assert(std::is_integral<IntegralType>::value, "Integer required");
        return static_cast<EnumType>(value);
    }

    template<typename EnumType,typename UnaryFunction>
    constexpr inline void setIntegralEnumValue(EnumType& enumValue, UnaryFunction integralWritingFunction)
    {
        // Since using reinterpret_cast on reference to underlying enum type is UB must declare underlying type value and write to it and then cast it to enum type
        // See discussion on /programming/19476818/is-it-safe-to-reinterpret-cast-an-enum-class-variable-to-a-reference-of-the-unde

        static_assert(std::is_enum<EnumType>::value,"Enum type required");

        auto enumIntegralValue = getIntegralEnumValue(enumValue);
        integralWritingFunction(enumIntegralValue);
        enumValue = toEnum<EnumType>(enumIntegralValue);
    }

उपयोग कोड

enum class MyEnum {
   first = 1,
   second
};

MyEnum myEnum = MyEnum::first;
std::cout << getIntegralEnumValue(myEnum); // prints 1

MyEnum convertedEnum = toEnum(1);

setIntegralEnumValue(convertedEnum,[](auto& integralValue) { ++integralValue; });
std::cout << getIntegralEnumValue(convertedEnum); // prints 2
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.