enum, switch, default, warnings
От: Roman Odaisky Украина  
Дата: 21.07.08 17:17
Оценка:
enum E { A, B, C };

int getE();

switch((E)getE())
{
case A: handleA(); break;
case C: handleC(); break; // ой, потеряли B!

default: oops("Value outside enum!");
}

Как сделать то же самое, но чтобы компилятор ругался, если я не обработаю часть значений enum? Если я выброшу default, то предупреждения будут («enumeration value ‘B’ not handled in switch»), но потеряется поведение по умолчанию. Можно вместо break сделать goto, а сразу за switch разместить код обработки ошибки. А как сделать по-человечески?
До последнего не верил в пирамиду Лебедева.
Re: enum, switch, default, warnings
От: Vamp Россия  
Дата: 21.07.08 17:20
Оценка:
RO>Как сделать ... чтобы компилятор ругался, если я не обработаю часть значений enum?

Вот не понимаю, какой смысл в этом предупреждении. Меня оно в свое время ужасно раздражало, потому что я просто так енумов в свитче не пропускаю. А если там больше 10 вариантов, то надо пересмотреть способ обработки, ибо такой ужасный огромный свитч очень трудно поддерживать.
Да здравствует мыло душистое и веревка пушистая.
Re: enum, switch, default, warnings
От: remark Россия http://www.1024cores.net/
Дата: 21.07.08 17:25
Оценка: 7 (1) +1
Здравствуйте, Roman Odaisky, Вы писали:

RO>Как сделать то же самое, но чтобы компилятор ругался, если я не обработаю часть значений enum? Если я выброшу default, то предупреждения будут («enumeration value ‘B’ not handled in switch»), но потеряется поведение по умолчанию. Можно вместо break сделать goto, а сразу за switch разместить код обработки ошибки. А как сделать по-человечески?



Как вариант вынести в отдельную функцию:
void handle()
{
 switch((E)getE())
 {
 case A: handleA(); return;
 case C: handleC(); return;
 }
 oops("Value outside enum!");
 assert(false);
}



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: enum, switch, default, warnings
От: Roman Odaisky Украина  
Дата: 21.07.08 18:14
Оценка:
Здравствуйте, remark, Вы писали:

RO>>Как сделать то же самое, но чтобы компилятор ругался, если я не обработаю часть значений enum? Если я выброшу default, то предупреждения будут («enumeration value ‘B’ not handled in switch»), но потеряется поведение по умолчанию. Можно вместо break сделать goto, а сразу за switch разместить код обработки ошибки. А как сделать по-человечески?


R>Как вариант вынести в отдельную функцию:

R>
R>void handle()
R>{
R> switch((E)getE())
R> {
R> case A: handleA(); return;
R> case C: handleC(); return;
R> }
R> oops("Value outside enum!");
R> assert(false);
R>}
R>

Это тот же goto, только в профиль. Меня еще что смущает: вдруг будет переполнение при приведении к типу enum? Оно здесь, по сути, не требуется, оно только для ворнингов.

(Qt любит в самых неожиданных местах возвращать -1 и смотреть, что из этого получится. Я тут перешел на 4.4, теперь эти неожиданные места обнаруживаются в более других неожиданных местах, чем раньше, а мне ловить.)
До последнего не верил в пирамиду Лебедева.
Re[3]: enum, switch, default, warnings
От: remark Россия http://www.1024cores.net/
Дата: 21.07.08 19:11
Оценка: -1
Здравствуйте, Roman Odaisky, Вы писали:

RO>Это тот же goto, только в профиль. Меня еще что смущает: вдруг будет переполнение при приведении к типу enum? Оно здесь, по сути, не требуется, оно только для ворнингов.


RO>(Qt любит в самых неожиданных местах возвращать -1 и смотреть, что из этого получится. Я тут перешел на 4.4, теперь эти неожиданные места обнаруживаются в более других неожиданных местах, чем раньше, а мне ловить.)



Может тогда как-то так:

enum E
{
  E1 = 1;
  E2 = 2;
  E4 = 4;
  E100 = 100;
};

E convert_to_E(int e)
{
  if (e < 1 || (e > 4 && e != 100) || e == 3)
    oops("Value outside enum!");
  return (E)e;
}

switch(convert_to_E(getE()))
{
case A: handleA(); break;
case C: handleC(); break;
}




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: enum, switch, default, warnings
От: Roman Odaisky Украина  
Дата: 21.07.08 20:25
Оценка:
Здравствуйте, remark, Вы писали:

R>Может тогда как-то так:

R>
R>enum E
R>{
R>  E1 = 1;
R>  E2 = 2;
R>  E4 = 4;
R>  E100 = 100;
R>};

R>E convert_to_E(int e)
R>{
R>  if (e < 1 || (e > 4 && e != 100) || e == 3)
R>    oops("Value outside enum!");
R>  return (E)e;
R>}

R>switch(convert_to_E(getE()))
R>{
R>case A: handleA(); break;
R>case C: handleC(); break;
R>}
R>

Вот где не хватает CTTI!

Сделал пока assert(ix >= 0) перед switch.
До последнего не верил в пирамиду Лебедева.
Re: enum, switch, default, warnings
От: Alexander G Украина  
Дата: 22.07.08 07:42
Оценка:
Здравствуйте, Roman Odaisky, Вы писали:

RO>
RO>enum E { A, B, C };

RO>int getE();

RO>switch((E)getE())
RO>{
RO>case A: handleA(); break;
RO>case C: handleC(); break; // ой, потеряли B!

RO>default: oops("Value outside enum!");
RO>}
RO>


Может так ?

E checkE(int e)
{
  switch(e)
  {
  case A:
  case B:
  case C:
    return static_cast<E>(e); // Проверено. Переполнений нет.
  }
  oops("Value outside enum!");
  return static_cast<E>(e); // Это не валидно, может переполнится, лучше oops кинет
}


void F()
{
  switch(/*E e =*/ checkE(getE()))
  {
  case A: handleA(); break;
  case C: handleC(); break; 
  } // ой, потеряли B!
}


PS: не проверял, в Студии такого ворнинга, похоже, нет.
Русский военный корабль идёт ко дну!
Re: enum, switch, default, warnings
От: ulong Россия  
Дата: 22.07.08 09:28
Оценка:
template< int valueA, typename handlerA, 
          int valueB, typename handlerB, 
          int valueC, typename handlerC >
struct Enum
{
    enum E { a = valueA, b = valueB, c = valueC };
    static void handle( E e )
    {
        switch( e )
        {
        case a: handlerA::handle(); break;
        case b: handlerB::handle(); break;
        case c: handlerC::handle(); break;
        default: assert( !"unhandled" );
        }
    }
};

struct handleA { static void handle() {} };
struct handleB { static void handle() {} };
struct handleC { static void handle() {} };

typedef Enum< 1, handleA, 
              2, handleB, 
              3, handleC > Handler;

...

Handler::handle( Handler::a );


не укажешь значение/обработчик — компилер ругнется

ps. (На всякий случай) не пиши так, внимательно прочекать switch на предмет проверки всех енумов будет правильней и в будущем легче для понимания коллег, которым твой код перейдет. ИМХО
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.