cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
88 stars 0 forks source link

enum class в switch case конструкций можно использовать если в switch стоит переменный с underlying type of enum #433

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +3, -7 Автор идеи: ??

Пример, который не скомплируется в с++11 или слудующих версий, потому что enum color не конвертируется на "int" . Но в switch case здесь никакое присваивание enum color на каких либо int не происходят.

enum class color{ red, blue, white };

int main()
{
     int value = read_value_from_anywhere_other_library();

    switch( value ) 
    {
         case color::red :  printf("This is a red color\n"); break;
         case color::bllue : printf("This is a blue color\n"); break;
         case color::white : printf("This is a white color\n"); break;
         default: printf("This is not a color\n");
    }

    return 0;
}

Предлагаю, добавить автогенерация оператор сравнение enum class с его underlying type . Чтобы легко сравнивать и использовать их в if else , switch case и других местах.

Тот пример , изменим и делаем работающий код для нынешного стандарт С++, будет UB:

enum class color{ red, blue, white };

int main()
{
    int value = read_value_from_anywhere_other_library();

   switch( (enum color) value ) // converting has a UB.
   {
       case color:: red: printf("This is a red color\n"); break;
       case color:: blue: printf("This is a blue color\n"); break;
       case color:: white: printf("This is a white color\n"); break;
       default: printf("This is a not color\n");break;
   }
}

Если не ошибаюсь, в с++17 конвертация целый число в enum class будет UB, если этот целый число значение имеет больше бит чем enum class элементы используется. В данном случий, enum class color -- элементам хватить 3 бит, а "value" переменный может имет любой допустимый значений.

apolukhin commented 3 years ago

Nate Reinar Windwood, 17 апреля 2019, 19:46 Контрпродуктивно: вся суть enum class в строгой типизации. Если нужен только скоупинг — засуньте enum в неймспейс.

Удалённый пользователь, 18 апреля 2019, 15:51 Nate Reinar Windwood, enum class очень удобно в компайл тайм вычеслениях, а реальный пример где можно использовать его в рантайм есть? Я свой проекте все enum ы перевел на enum class и об этом сожелел, пришлось для каждого enum class написать операция сравнений на int . Конца, концов отказал от этий идей.

Удалённый пользователь, 18 апреля 2019, 15:57

// Вот один пример.

struct table_row
{
    int id;
    int color;
};

enum class color{  red, blue, white } ;

void read_from_db(table_row& row)
{

    row =  read_from_outside_library();

    // Не комплириуется без  operator != (  int , enum color )  overload.

    if ( row.color != color::red && row.color != color::blue && row.color != color.white )
        throw std::runtime_error("row.color invalid");
}

Удалённый пользователь, 18 апреля 2019, 16:05 Я не предлагаю, изменить каких либо свойства enum class а.

Предлагаю, implicit добавить operation == , != , < , > , <= , >= с enum class and its underlying-type.

Например, если вот эту компилятор сам генерирует, будет здорово!

template<  typename Enum > 
bool operator  == ( Enum e, typename std::underlying_type<Enum>::type value)
{
         return static_cast< typename std::underlying_type<Enum>::type > ( e ) == value ;
}

template<  typename Enum > 
bool operator  == (  typename std::underlying_type<Enum>::type value , Enum e)
{
         return static_cast< typename std::underlying_type<Enum>::type > ( e ) == value ;
}

Виктор Губин, 2 августа 2019, 12:38 Чем вас не устраивает

switch( static_cast<color>(value) )

?

Внутри enum так или иначе это unsigned integer, есть только возможность "подрезать" тип. Скажем для Windows/DOS символов консоли,

enum class color: uint8_t { red = 0x04; green = 0x02; blue = 0x01 };

естественно static_cast попросту сведет байт к двойному слову.

К сожалению привять дополнительное константное значаение другого типа прямо внути enum С++ нельзя, хотя было-бы очень полезным:

enum class error_condition  {
   ok("no error") = 0,
   file_not_found("no such file or directory") = 1
public:
   constexp const char* message() const noexcept {
     return msg_;
   }
private:
  explicit constexpr  error_condition(const char* msg) noexcept:
    msg_(msg)
  {}
  const char* msg_;
}

Тогда вообще отпадет надобность писать switch, достаточно просто спросить у константы

ec.message()
  1. В других языках такое уже есть :)
pavel-zhigulin commented 3 years ago

Чем вас не устраивает

switch( static_cast<color>(value) )

?

Это UB, если value нековертируем

template<  typename Enum > 
bool operator  == ( Enum e, typename std::underlying_type<Enum>::type value)
{
         return static_cast< typename std::underlying_type<Enum>::type > ( e ) == value ;
}

template<  typename Enum > 
bool operator  == (  typename std::underlying_type<Enum>::type value , Enum e)
{
        return static_cast< typename std::underlying_type<Enum>::type > ( e ) == value ;
}

А это - почти полное стирание грани между enum class и enum classic. Если добавить еще operator=, то будет совсем полное.

Лучше бы в стандартную библиотеку добавить такое:

enum class Enum
{
    X = 1,
    Y = 100,
};

std::is_enumerated<Enum>(1); // true
std::is_enumerated<Enum>(101); // false

Объявить реализацию как unspecified и жить спокойно в ожидании нормальной рефлексии (которую хрен пойми когда привезут).