একটি এনাম শ্রেণি অন্তর্নিহিত ধরণে রূপান্তর করা যায়?


112

enum classক্ষেত্রকে অন্তর্নিহিত ধরণে রূপান্তর করার কোনও উপায় আছে কি ? আমি ভেবেছিলাম এটি স্বয়ংক্রিয় হবে, তবে দৃশ্যত তা নয়।

enum class my_fields : unsigned { field = 1 };

unsigned a = my_fields::field;

সেই দায়িত্বটি জিসিসি প্রত্যাখ্যান করেছে। error: cannot convert 'my_fields' to 'unsigned int' in assignment


4
আপনি যদি অন্তর্নিহিত ধরণের রূপান্তর করতে চান তবে ব্যবহার করুন enum
পাব্বি

1
এফওয়াইআই, এই নিয়মটি সংজ্ঞায়িত করা হয়েছে [C++11: 7.2/9]
অরবিটে হালকাতা রেস

5
@ পাব্বি দুঃখজনকভাবে অব্যাহত 'এনাম' সমস্ত গণনাকারীর সাথে বাহ্যিক ক্ষেত্রকে দূষিত করছেন। হায় আফসোস উভয় বিশ্বেরই সেরা নেই (যাইহোক সি ++ 14 হিসাবে) যা পরিচ্ছন্নভাবে স্কোপকে বাসা বেঁধে দেয় এবং স্পষ্টভাবে বেস টাইপকে রূপান্তর করে (যা C ++ কীভাবে অন্যান্য শ্রেণীর উত্তরাধিকারকে পরিচালনা করে তার সাথে সামঞ্জস্যপূর্ণ নয়, যখন আপনি আরও বেশি উত্পন্ন প্রকারটি পাস করেন একটি বেস প্রকার গ্রহণ করে এমন কোনও ফাংশনের মান বা রেফারেন্স)।
ডোয়াইন রবিনসন

2
@ ডোয়েনরোবিনসন হ্যাঁ আছে কাঠামোর ভিতরে বা একটি অনির্বাচিত এনামটি আটকে দিন (আরও বেশি পছন্দ করা যায়) একটি নেমস্পেসে। এইভাবে এটি স্কোপড এবং এখনও অন্তর্নিহিত অন্তর্নির্মিত রূপান্তর আছে। (যদিও আপনাকে কেন একটি
ইনট্রিতে

উত্তর:


178

আমি মনে করি আপনি অন্তর্নিহিত প্রকারটি জানতে std :: অন্তর্নিহিত_প্রকারটি ব্যবহার করতে পারেন এবং তারপরে কাস্ট ব্যবহার করতে পারেন:

#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
@ রায়ানহাইনিং: ধন্যবাদ (বিটিডব্লিউ, আপনার constexprভবিষ্যতেও রয়েছে; আসলে আমি যা ছিলাম তার চেয়ে অনেক বেশি শক্তিশালী ২০১৩: পি)
নওয়াজ

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

অন্যরা যেমন উল্লেখ করেছে যে এখানে কোনও অন্তর্নিহিত castালাই নেই তবে আপনি একটি স্পষ্ট ব্যবহার করতে পারেন 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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.