Сергей Борщ 186 January 26, 2007 Posted January 26, 2007 · Report post задача в следующем: 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. явное преобразование не хочется потому что можно случайно преобразовать совсем не то, что нужно. Quote Share this post Link to post Share on other sites More sharing options...
v_shamaev 0 January 26, 2007 Posted January 26, 2007 · Report post Теперь если я пытаюсь сделать device1_cmd = CMD9; то получаю ошибку a value of type "device2_cmd" cannot be used to initialize an entity of type "device1_cmd". Что правильно, и ради этого все enum и затевались. Это же название типа, а не имя переменной. Определите переменную типа device1_cmd, а уж ей присваивайте значение Quote Share this post Link to post Share on other sites More sharing options...
zltigo 4 January 26, 2007 Posted January 26, 2007 · Report post Ну это ведь действительно в плюсах определения ТИПОВ. device1_cmd = CMD1; device1_cmd aaaa; ...... device1_cmd aaaa = (device1_cmd)CMD1; По идее должно работать, хотя насколько мне помнится, никаких официальных требований к возможности такого преобразования не накладывается - посему, как "повезет". Вообще это извращение enum. Для "красоты" (device1_cmd)CMD1 можно в макросик замаскировать. А уж "НЕЯВНОЕ ПРЕОБРАЗОВАНИЕ" ни в какие ворота не лезет - не будет такого. Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 186 January 26, 2007 Posted January 26, 2007 · Report post 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; а я хочу этого избежать. Quote Share this post Link to post Share on other sites More sharing options...
zltigo 4 January 26, 2007 Posted January 26, 2007 · Report post Для чего заводится enum? Чтобы ненароком не присвоить переменной значение которого она никогда не может иметь. Ага, и именно по этой причине желаемые НЕЯВНЫЕ прообразования с этим типом не могут быть в принципе. Если я делаю приведение типов вручную, компилятор уже ничего не проверяет. Он пропустит и aaaa = (device1_cmd)CMD9; а я хочу этого избежать. Лучше вручную, чем неявно. Fuzzy logic хочется :) :) Для пущей "безопасности" можно пробовать городить еще макрос для присвоения с наворотами - имя переменной в и CMDx намеспайсинг спрятать - прямо уже не присвоишь. Quote Share this post Link to post Share on other sites More sharing options...
kovalchuk_i_v 0 January 26, 2007 Posted January 26, 2007 · Report post C++ позволяет переопределять операции. ихмо стоит попробовать определить операцию присвоения для типов device1_cmd и device2_cmd . Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 186 January 26, 2007 Posted January 26, 2007 · Report post ихмо стоит попробовать определить операцию присвоения для типов 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 не пересеклись. Quote Share this post Link to post Share on other sites More sharing options...
Olej 1 January 27, 2007 Posted January 27, 2007 · Report post 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 Александреску :) ... Попробуйте. Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 186 January 27, 2007 Posted January 27, 2007 · Report post А как вам понравится такое "проходит" cmd1 = device1_cmd( CMD4 | CMD5 ); Так ведь это явное приведение. Против этого я и не протестую :) Вы хотите использовать enum совсем не в том качестве, для которого они предназначеныспасибо за подробное объяснение. Кажется, проясняется. Тем более, нереалистично желание переложить контроль допустимости значений на компилятор (как я понял, вы хотели бы чтоб это были проверки времени компиляции а не времени исолнения): значение, которое вы захотите присваивать может динамически измениться на выполнении (как в примере) - кто тогда будет проверять его допустимость? Ну почему же нереалистично? Для классов реалистично "и тут хочу!". А во время исполнения сдуру можно все что угодно через указатели привести и никакой компилятор не спасет. С классами понятно - добавил конструктор и все. А как с enum? Вот и определите то что вы хотите внутри класса (вложив внутрь класса) ... определите для него "=" ... Видимо так и придется. Только если я помещу enum внутрь класса, то мне придется постоянно писать command_t::CMD1, а это несколько утомительно и опять же требует помнить какие команды описаны в каком классе. Ладно, буду городить класс. P.S. предполагаю (чутьё подсказывает :) ) - что то что вы хотите вы могли бы определить используя template ... в стиле a'la Александреску :) ... Попробуйте. Кто такой Александреску? Можно пример его стиля? Quote Share this post Link to post Share on other sites More sharing options...
Olej 1 January 27, 2007 Posted January 27, 2007 · Report post А как вам понравится такое "проходит" 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 стр. Много обсуждаемая книжка: одни принимают с восторгом, другия ругаются брызгая слюной ;). Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 186 January 28, 2007 Posted January 28, 2007 · Report post Да, но явное приведение того, что приводится не должно ни в каком случае: среди допустимых значений перечисления 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. Тема не закрыта, рад выслушать любые альтернативные идеи. Quote Share this post Link to post Share on other sites More sharing options...
Olej 1 January 28, 2007 Posted January 28, 2007 · Report post Да, можно. Но личная практика показывает что это верный шаг к путанице и трудноотлавливаемым ошибкам. Мы, возможно, говорим о несколько разных вещах... Для пояснения того, что я имею в виду - я поискал файлы *.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 Quote Share this post Link to post Share on other sites More sharing options...