Перейти к содержанию
    

enum в С++

задача в следующем:

enum command_t {CMD1, CMD2, CMD3 };
enum device1_cmd {CMD4 = CMD3, CMD5, CMD6};
enum device2_cmd {CMD7 = CMD3, CMD8, CMD9};

т.е. есть некий общий набор команд и его расширения специфичные для разных устройств.

Теперь если я пытаюсь сделать

device1_cmd = CMD9;

то получаю ошибку a value of type "device2_cmd" cannot be used to initialize an entity of type "device1_cmd". Что правильно, и ради этого все enum и затевались.

но такую же ошибку я получаю и на

device1_cmd = CMD1;

а вот этого не хочется. Т.е. хочется объявить оператор неявного преобразования из command_t в device1_cmd. Как это сделать?

 

P.S. явное преобразование не хочется потому что можно случайно преобразовать совсем не то, что нужно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Теперь если я пытаюсь сделать

device1_cmd = CMD9;

то получаю ошибку a value of type "device2_cmd" cannot be used to initialize an entity of type "device1_cmd". Что правильно, и ради этого все enum и затевались.

 

Это же название типа, а не имя переменной. Определите переменную типа device1_cmd, а уж ей присваивайте значение

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну это ведь действительно в плюсах определения ТИПОВ.

 

device1_cmd = CMD1;

 

device1_cmd aaaa;
......
device1_cmd aaaa = (device1_cmd)CMD1;

По идее должно работать, хотя насколько мне помнится, никаких официальных требований к возможности такого преобразования не накладывается - посему, как "повезет".

Вообще это извращение enum. Для "красоты" (device1_cmd)CMD1 можно в макросик замаскировать.

А уж "НЕЯВНОЕ ПРЕОБРАЗОВАНИЕ" ни в какие ворота не лезет - не будет такого.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

device1_cmd = CMD9;

Это же название типа, а не имя переменной. Определите переменную типа device1_cmd, а уж ей присваивайте значение

Извиняюсь, кончно же у меня что-то вроде

device1_cmd cmd1;
cmd1 = CMD5;    // проходит, ибо "родное"
cmd1 = CMD9;    // не проходит, и правильно
cmd1 = CMD1;    // не проходит, а я хочу чтоб проходило.

Вопрос - как сделать так, чтобы значение типа command_t неявно(!) при необходимости преобразовывалось к device1_cmd. С классами понятно - добавил конструктор и все. А как с enum?

 

aaaa = (device1_cmd)CMD1;

По идее должно работать

Да, работает. Но меня это не устраивает. Для чего заводится enum? Чтобы ненароком не присвоить переменной значение которого она никогда не может иметь. Ошибка отлавливается компилятором и сразу. Если я делаю приведение типов вручную, компилятор уже ничего не проверяет. Он пропустит и

aaaa = (device1_cmd)CMD9;

а я хочу этого избежать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для чего заводится enum? Чтобы ненароком не присвоить переменной значение которого она никогда не может иметь.

Ага, и именно по этой причине желаемые НЕЯВНЫЕ прообразования с этим типом не могут быть в принципе.

Если я делаю приведение типов вручную, компилятор уже ничего не проверяет. Он пропустит и

aaaa = (device1_cmd)CMD9;

а я хочу этого избежать.

Лучше вручную, чем неявно.

Fuzzy logic хочется :) :)

Для пущей "безопасности" можно пробовать городить еще макрос для присвоения с наворотами - имя переменной в и CMDx намеспайсинг спрятать - прямо уже не присвоишь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

C++ позволяет переопределять операции. ихмо стоит попробовать определить операцию присвоения для типов device1_cmd и device2_cmd .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ихмо стоит попробовать определить операцию присвоения для типов device1_cmd и device2_cmd .
1)Пробовал. Или я что-то не так делал, но компилятор ругается "Оператор присваивания должен быть нестатическим членом".

2)Все равно оператор присваивания не решает проблемы, ибо не работает при инициализации структуры через {}

 

 

Ага, и именно по этой причине желаемые НЕЯВНЫЕ прообразования с этим типом не могут быть в принципе.
Ну почему? Я же определяя эту операцию преобразования явно указываю какие именно типы преобразовывать можно. Значит остальные неявно нельзя.

Fuzzy logic хочется :) :)

Для пущей "безопасности" можно пробовать городить еще макрос для присвоения с наворотами - имя переменной в и CMDx намеспайсинг спрятать - прямо уже не присвоишь.

Почему fuzzy? Для классов это нормальная операция:

class A
{
public:
   A(int);
}

class B
{
public:
   B(int);
   B(A);
}

А макросы в данном случае - некрасивое решение.

неймспасинг тоже не проходит - пробовал. Мне надо "скрестить" command_t c device1_cmd и с device2_cm2, и чтобы при этом device1_cmd и device2_cmd не пересеклись.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

device1_cmd cmd1;
cmd1 = CMD5;    // проходит, ибо "родное"
cmd1 = CMD9;    // не проходит, и правильно
cmd1 = CMD1;    // не проходит, а я хочу чтоб проходило.

Вопрос - как сделать так, чтобы значение типа command_t неявно(!) при необходимости преобразовывалось к device1_cmd.

 

А как вам понравится такое "проходит"

#include <iostream>
using std::cout;
using std::endl;

enum command_t { CMD1, CMD2, CMD3 = 3 };
enum device1_cmd { CMD4 = CMD3, CMD5 = 8, CMD6 = 12 };
enum device2_cmd { CMD7 = CMD3, CMD8, CMD9 };

int main( int argc, char* argv[] ) {
   device1_cmd cmd1;
   cmd1 = CMD5;    // проходит, ибо "родное"
   cmd1 = device1_cmd( CMD4 | CMD5 );
   cout << cmd1 << endl;
   exit( EXIT_SUCCESS );
};

и чтоб не быть голословным - вот вам прогон (gcc 3.3.5 - QNX 6.3.2):

/root/enum # enum
11

 

Вы хотите использовать enum совсем не в том качестве, для которого они предназначены: enum фактически не вводит нового класса, а всего лишь определяет синоним, но за счёт именной (а не структурной) типизации С++, между ними запрещены преобразования (но не запрещено присвоить "хрен знает что", что и делается в примере выше). Именно из-за этого вы не можете (и не сможете) переопределить операцию "=" - эта операция должна определяться как член класса (внутри класса) - а класса то нет? :ohmy: :)

P.S. специально не отвечал вчера - засомневался :) , решил перепровериться у Страуструпа - у него утверждается в точности то же самое.

 

Тем более, нереалистично желание переложить контроль допустимости значений на компилятор (как я понял, вы хотели бы чтоб это были проверки времени компиляции а не времени исолнения): значение, которое вы захотите присваивать может динамически измениться на выполнении (как в примере) - кто тогда будет проверять его допустимость?

 

С классами понятно - добавил конструктор и все. А как с enum?

 

Вот и определите то что вы хотите внутри класса (вложив внутрь класса) ... определите для него "=" ... но и тут будут проблемы - ну и что вы будуте делать когда выясниться что присваивается недопустимое значение?

 

P.S. предполагаю (чутьё подсказывает :) ) - что то что вы хотите вы могли бы определить используя template ... в стиле a'la Александреску :) ...

Попробуйте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А как вам понравится такое "проходит"

   cmd1 = device1_cmd( CMD4 | CMD5 );

Так ведь это явное приведение. Против этого я и не протестую :)

Вы хотите использовать enum совсем не в том качестве, для которого они предназначены
спасибо за подробное объяснение. Кажется, проясняется.

 

Тем более, нереалистично желание переложить контроль допустимости значений на компилятор (как я понял, вы хотели бы чтоб это были проверки времени компиляции а не времени исолнения): значение, которое вы захотите присваивать может динамически измениться на выполнении (как в примере) - кто тогда будет проверять его допустимость?
Ну почему же нереалистично? Для классов реалистично "и тут хочу!". А во время исполнения сдуру можно все что угодно через указатели привести и никакой компилятор не спасет.

С классами понятно - добавил конструктор и все. А как с enum?

Вот и определите то что вы хотите внутри класса (вложив внутрь класса) ... определите для него "=" ...

Видимо так и придется. Только если я помещу enum внутрь класса, то мне придется постоянно писать command_t::CMD1, а это несколько утомительно и опять же требует помнить какие команды описаны в каком классе. Ладно, буду городить класс.

 

P.S. предполагаю (чутьё подсказывает :) ) - что то что вы хотите вы могли бы определить используя template ... в стиле a'la Александреску :) ...

Попробуйте.

Кто такой Александреску? Можно пример его стиля?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А как вам понравится такое "проходит"

   cmd1 = device1_cmd( CMD4 | CMD5 );

Так ведь это явное приведение. Против этого я и не протестую :)

Да, но явное приведение того, что приводится не должно ни в каком случае: среди допустимых значений перечисления device1_cmd - не допускается и не предусмотрено значение 11! (только: CMD4 = 3,

CMD5 = 8, CMD6 = 12 - что такое 11 ?).

 

Ну почему же нереалистично? Для классов реалистично "и тут хочу!". А во время исполнения сдуру можно все что угодно через указатели привести и никакой компилятор не спасет.

Именно поэтому допустимость приведения (присвоения) нужно контролировать на фазе исполнения, а не компиляции.

 

Видимо так и придется. Только если я помещу enum внутрь класса, то мне придется постоянно писать command_t::CMD1, а это несколько утомительно и опять же требует помнить какие команды описаны в каком классе. Ладно, буду городить класс.

Не обязательно оперировать сложными именами типа command_t::CMD1 - вы можете #define определить внутренние имена как простые внешние, так весь QNX переопределён.

P.S. может вам покажется полезным кое-что о трюках QNX, которые можно перенести в другие окружения, посмотреть здесь:

http://qnxclub.net/modules.php?name=Forums...ewforum&f=7

 

Кто такой Александреску? Можно пример его стиля?

Андрей Александреску "Современное проектирование на С++" Пер. с англ. - М. : Издательский дом "Вильямс", 2002. - 336 стр.

Много обсуждаемая книжка: одни принимают с восторгом, другия ругаются брызгая слюной ;).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, но явное приведение того, что приводится не должно ни в каком случае: среди допустимых значений перечисления device1_cmd - не допускается и не предусмотрено значение 11!

...........

Именно поэтому допустимость приведения (присвоения) нужно контролировать на фазе исполнения, а не компиляции.

Как говорил мой бывший шеф "Полный" Лемис "сдуру можно и х.. сломать". Мы говорим о разном. Я хотел разрешить совершенно конкретное неявное приведение.

Не обязательно оперировать сложными именами типа command_t::CMD1 - вы можете #define определить внутренние имена как простые внешние, так весь QNX переопределён.
Да, можно. Но личная практика показывает что это верный шаг к путанице и трудноотлавливаемым ошибкам.

 

P.S. может вам покажется полезным кое-что о трюках QNX, которые можно перенести в другие окружения, посмотреть здесь:

http://qnxclub.net/modules.php?name=Forums...ewforum&f=7

..........

Андрей Александреску "Современное проектирование на С++" Пер. с англ. - М. : Издательский дом "Вильямс", 2002. - 336 стр.

Много обсуждаемая книжка: одни принимают с восторгом, другия ругаются брызгая слюной ;).

Спасибо, пошел изучать.

 

P.S. Тема не закрыта, рад выслушать любые альтернативные идеи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, можно. Но личная практика показывает что это верный шаг к путанице и трудноотлавливаемым ошибкам.

 

Мы, возможно, говорим о несколько разных вещах...

Для пояснения того, что я имею в виду - я поискал файлы *.h в определениях QNX (где это встречается "валом"), но как-то сразу не нашёл :angry2: ... но и эти определения заимствованы в QNX из FreeBSD и, ещё большим образом, из NetBSD, где этого будет полно... Я не нашёл быстро файлы системных определений, но зато нашёл искусственный пример, который когда-то давненько писал для студентов, для объяснений таких переопределений:

#include <stdlib.h>

struct PI {
   void* ____p;
   int   ____i;
};

union L{
   struct {
      long long __d1;
      long long __d2;
   } I;
   struct {
      struct PI __pi1;
      struct PI __pi2;
   } V;
   char c[ 0 ];
};
#define d1 I.__d1
#define d2 I.__d2
#define p1 V.__pi1.____p
#define p2 V.__pi2.____p

typedef union L Z;

int main() {
   Z a;
   a.d1 = 1;
   a.d2 = 2;
   printf( "%X %X\n", a.p1, a.p2 );
   int i;
   for( i = 0; i < sizeof( Z ) / sizeof( *a.c ); i++ )
      printf( "%d ", a.c[ i ] );
   printf( "\n" );
   return 0;
};

- обратите внимание - как a2.V.__pi2.____p превратилось в простенькое :tongue: a.p2 - это просто синонимическая замена, которую 1 раз сделали - и забыли ("... взула и забула..."(с) - так в рекламе говорят? :laugh: ). При чём в определениях ОС (QNX, FreeBSD, NetBSD) перед такими определениями стоят #ifndef с комментариями что-то в роде: "для тех компиляторов С, которые не допускают неименнованные компоненты внутри структур" ... а какие допускают? - стандарт ANSI или K&R не допускают ничего подобного, но я знаю только 1 такой компилятор - Watcom, который позволял и был очень популярный. Т.е. мы просто "вытаскиваем" в глубине определённые составные имена "на поверхность" (вот, собственно, для того, чтобы они потом, когда уже "забудем", никогда не пересеклись с реальными именами - внутренним полям они и дают такие "замысловатые" названия с _ на начале или на конце) - никаких неприятностей после таких статических переопределений ожидать не стоит.

 

P.S. (добавлено позже) вот только сейчас вспомнил, что этот вопрос подробнее обсуждался вот здесь:

http://qnxclub.net/modules.php?name=Forums...;highlight=pure

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...