На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> case ругается на поле static const
    Здравствуйте!

    Внезапно столкнулся с проблемкой.

    Объявил класс со статическими константами:
    ExpandedWrap disabled
      class foo
      {
      public:
      static const int alpha;
      static const int beta;
      };
       
      const int foo::alpha = _XXX_SIMBOL_ALPHA;
      const int foo::beta = _XXX_SIMBOLBETA;


    Ну и тут чудеса.
    В функции main (из main.obj)

    ExpandedWrap disabled
      switch( val )
      {
      case foo::alpha:
      case foo::beta:
      break;
      default:
      break;
      }


    Компилятор ms vs 2015 сказал, что foo::alpha не является константой!

    Но когда я перенёс этот switch в конструктор foo (в foo.obj), то всё чудесно отработало.

    Что тут можно сделать? Что тут можно поправить? Как сказать switch, что у меня действительно константы?

    В инете наткнулся на описание схожих ситуаций. Вроде бы банальность. А решения нет.

    Проскакивала мысль на счёт constexpr. Но компилятор хочет, чтоб я ему сразу предоставил значение. Чего-то там как-то не так.
      Несколько странный вопрос. Ибо: компилирует, скажем, компилятор такой левый файл с таким левым switch'ем, а вы опосля взяли и переправили значение. В итоге - несогласованность. :oops:
        Цитата Eric-S @
        Что тут можно сделать?

        Использовать enum или попробовать инициализировать поля прямо в объявлении класса
        ExpandedWrap disabled
          static const int beta = _XXX_SIMBOLBETA;
        Сообщение отредактировано: shm -
          Цитата Славян @
          Несколько странный вопрос. Ибо: компилирует, скажем, компилятор такой левый файл с таким левым switch'ем, а вы опосля взяли и переправили значение. В итоге - несогласованность. :oops:

          Замечание правомочно.
          Но ведь я и enum class могу изменить, с тем же успехом.

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

            Добавлено
            Цитата Eric-S @
            Но ведь я и enum class могу изменить, с тем же успехом.

            Не можешь.
            Сообщение отредактировано: shm -
              Цитата shm @
              Использовать enum или попробовать инициализировать поля прямо в объявлении класса
              ExpandedWrap disabled
                static const int beta = _XXX_SIMBOLBETA;

              Ох. Хорошо бы. Но эти константы, тянутся из одной страшненькой библиотеки. И я хотел бы скрыть эту пакость.

              Но сейчас подумываю на счёт промежуточного enum.
              В том смысле, что значение перечисления будет автоматом.
              А при необходимости, получить константу, внутри будет switch, который конвертнёт константу enum в константу int.
              ExpandedWrap disabled
                int to_int( foo_enum val )
                {
                switch( val )
                {
                 
                case foo_enum::alpha:
                return _XXX_SIMBOL_ALPHA;
                 
                case foo_enum::beta:
                return _XXX_SIMBOL_BETA;
                 
                }
                }


              Добавлено
              Цитата shm @
              компилятор правильно ругается и действительно ничего с этим не сделать, т. к. это не константа а константная переменная, что не одно и то же.

              Ругается правильно. Справедливо, правомочно и логично.
              Но неужели нет ни одного внятного трюка для укращения?
                Цитата Eric-S @
                Ох. Хорошо бы. Но эти константы, тянутся из одной страшненькой библиотеки. И я хотел бы скрыть эту пакость

                Ну а зачем ты выносишь тогда эти константы наружу? Сделай обертки для функций из этой библиотеки и все.

                Добавлено
                А вообще, это ж макросы. Просто скопируй их оттуда к себе и не парься.
                  Цитата Eric-S @
                  Объявил класс со статическими константами:
                  Скрытый текст
                  ExpandedWrap disabled
                    class foo
                    {
                    public:
                    static const int alpha;
                    static const int beta;
                    };
                     
                    const int foo::alpha = _XXX_SIMBOL_ALPHA;
                    const int foo::beta = _XXX_SIMBOLBETA;


                  Ну и тут чудеса.
                  В функции main (из main.obj)

                  ExpandedWrap disabled
                    switch( val )
                    {
                    case foo::alpha:
                    case foo::beta:
                    break;
                    default:
                    break;
                    }


                  Компилятор ms vs 2015 сказал, что foo::alpha не является константой!

                  а у меня все компилирует :D

                  пробовал vs2008

                  щас протестил в vs2010-vs2015 все компилирует :D :D

                  или я не правильно понял? :unsure:
                  Эриксон проправь меня, а то я с ума сойду :D
                  Сообщение отредактировано: Cfon -
                    Цитата Cfon @
                    Эриксон проправь меня, а то я с ума сойду :D

                    Ты разделил единицы трансляции? Должно быть два объектных файла: foo.obj и main.obj.

                    Добавлено
                    Цитата Олег М @
                    Ну а зачем ты выносишь тогда эти константы наружу? Сделай обертки для функций из этой библиотеки и все.

                    Как раз пишу статическую lib, в качестве обёртки.

                    Но в частности, эти константы нужны пользователю, для обработки callback функции.

                    Пользователь пишет функцию.
                    Регистрирует её в моей обёртке.
                    Затем библиотека дёргает эту функцию.
                    А пользователь должен обработат сообщение через switch.
                    Можно конечно if. Всё же функция простенькая, не какой-то там WinProc.

                    Добавлено
                    Цитата Олег М @
                    А вообще, это ж макросы. Просто скопируй их оттуда к себе и не парься.

                    Угу. Ну да... А хорошо ли так делать?

                    Подход гарантировано работающий сечас.
                    Но в будущем ломабельный. И просто неэтичный.

                    Добавлено
                    Цитата shm @
                    Цитата Eric-S @
                    Но ведь я и enum class могу изменить, с тем же успехом.

                    Не можешь.

                    Не... Я в том смысле, что если я изменю enum в одном файле, то придётся перекомпилировать все файлы, где используется этот enum.
                      Цитата Eric-S @
                      Я в том смысле, что если я изменю enum в одном файле, то придётся перекомпилировать все файлы, где используется этот enum.

                      Иии?
                        Цитата Славян @
                        Несколько странный вопрос. Ибо: компилирует, скажем, компилятор такой левый файл с таким левым switch'ем, а вы опосля взяли и переправили значение. В итоге - несогласованность. :oops:


                        Цитата Eric-S @
                        Замечание правомочно.
                        Но ведь я и enum class могу изменить, с тем же успехом.

                        Понятно, что такая ситуация возможно. Я о ней знаю.
                        Но неужели ничего нельзя поделать?


                        Значит всё равно придётся перекомпилировать! Единственная сложность в дополнительной проверки изменений.

                        Добавлено
                        Цитата shm @
                        Иии?

                        Да, нет. Ничо. Это я так, причетаю. Понятно же, что с enum, компилятору легче перепроверить кто когда изменился, поскольку enum открыт всем ветрам, опубликованный в хидере.
                        Сообщение отредактировано: Eric-S -
                          Цитата Eric-S @

                          Угу. Ну да... А хорошо ли так делать?

                          Подход гарантировано работающий сечас.
                          Но в будущем ломабельный. И просто неэтичный


                          В общем случае – нехорошо. А в частном – оцениваешь, стоит ли эта библиотека прилагаемых усилий, да еще в runtime. Чаще бывает, что проще скопировать значения.
                            Цитата Олег М @
                            В общем случае – нехорошо.

                            Потом будет лениво переделывать. Да и пользоватся странным интерфейсом стрёмно.
                            Так что, если делать, то максимально хорошо.
                            А в противном случае, проще юзать библиотеку, без всяких обёрток.
                              Цитата Eric-S @
                              Потом будет лениво переделывать. Да и пользоватся странным интерфейсом стрёмно.
                              Так что, если делать, то максимально хорошо.

                              Проблема в том, что ты пытаешься перенести в runtime решение задачи - сравнение и сопоставление констант - которая может и должна решаться в compile-time. В данном случае, если тебе очень не хочется выносить наружу заголовок твоей библиотеки, можно просто сделать свой enum или свои константы совпадающие по значению с библиотечными. И проверять где-нибудь их соответствие при помощи static_assert.
                                Вообщем я сделал свой enum class, с альтернативными кодами.
                                И две функции конвертирующие туда и обратно, через тот же самый switch.
                                Заодно, в секции default, воткнул throw invalid_argument.
                                Отработало всё нормально. Жаль, что моя версия компилятора не может это сделать constexpr, а в остальном результат устраивает.

                                Но если у кого появятся альтернативные решения, прошу отписаться!

                                Добавлено
                                Цитата Олег М @
                                можно просто сделать свой enum или свои константы совпадающие по значению с библиотечными. И проверять где-нибудь их соответствие при помощи static_assert.

                                Да! Это тоже хорошее, правильное решение.
                                Проверять через static_assert.
                                А приводить через reinterpret_cast?

                                Добавлено
                                Сейчас коммит оформлю, чтоб сохранить изменения с вариантом runtime. И попробую переделать с вариантом compile-time.
                                  Цитата Eric-S @
                                  Проверять через static_assert.
                                  А приводить через reinterpret_cast?

                                  Как хочешь. А их нужно вообще приводить, там разве не int?

                                  Добавлено
                                  Кстати, насчёт runtime - вот ты скомпилировал новую версию, константы у тебя, допустим, разошлись - и как ты это отслеживаешь?
                                    Цитата Олег М @
                                    Как хочешь. А их нужно вообще приводить, там разве не int?

                                    Изначально у меня действительно был int.
                                    Но стремясь к типобезопастности, правильнее сделать enum class.
                                    Именно его я сейчас и сделал.

                                    Эм-эм-эм... Какой вопрос хороший, с подковырочкой-то!

                                    Ну ладно. Сознаюсь, что сделал не идиально и не полноценно. Но пока хватало.

                                    1. в makefile добавил зависимость с cpp файлом, в котором были объявлены константы.

                                    2. после разных приключений и интересной идеи с хабра, в ответственных местах, создаю константу версии:
                                    enum{ __version_num = 1 };
                                    Ну а в местах, которые зависят, проставил
                                    static_assert( 1 == component_name::__version_id, "update component_name" );
                                    Остаётся своевременно обновлять номер версии.
                                    Но по факту это актуально лишь для контроля в методах за изменениями сложных полей класса.

                                    3. с динамическими компонентами. Ну, когда всё совсем сложно. Обычно для отдельной dll.
                                    Там действительно остаётся только run-time.
                                    Создаю функцию инициализации библиотеки:
                                    ExpandedWrap disabled
                                      #define current_major_version 2
                                      #define current_minor_version 86
                                       
                                      void _component_initialize( int major_version, int minor_version )
                                      {
                                       
                                      if( current_major_version != major_version )
                                      {
                                      throw invalid_version( "conflict major version" );
                                      }
                                       
                                      if( current_minor_version <= major_version )
                                      {
                                      throw invalid_version( "conflict minor version" );
                                      }
                                      }


                                    А там где библиотека юзается, то дёргаю эту функцию через макрос.
                                    ExpandedWrap disabled
                                      #define component_initialize() _component_initialize( current_major_version, current_minor_version );


                                    Если библиотека обновилась, а прога хочет старую, то упс и обломс.

                                    Трюк, вообщем-то прокатывает и для статических библиотек. Но прописывать такое лениво. Проще прописать зависимость в makefile.
                                    Сообщение отредактировано: Eric-S -
                                      Цитата Eric-S @
                                      Но по факту это актуально лишь для контроля в методах за изменениями сложных полей класса.


                                      По факту, у тебя получился код, который просто преобразует одно число в другое, константы в рантайме. Больше никакой осмысленной нагрузки не несёт. Контроль версий здесь поможет слабо. Нужен контроль именно этих констант.

                                      Добавлено
                                      Я бы сделал примерно так

                                      ---h-file
                                      ExpandedWrap disabled
                                        #define RETCODES \
                                            ITEM(XXX_SIMBOL_ALPHA, 1) \
                                            ITEM(XXX_SIMBOLBETA, 2) \
                                         
                                        enum
                                        {
                                        #define ITEM(name, value) _##name = value,
                                            RETCODES
                                        #undef ITEM
                                        }
                                         
                                        ----cpp-file
                                        #include <somelib.h>
                                         
                                        #define ITEM(name, value) static_assert(_##name == name);
                                            RETCODES
                                        #undef ITEM
                                      Сообщение отредактировано: Олег М -
                                        Цитата Олег М @
                                        По факту, у тебя получился код, который просто преобразует одно число в другое, константы в рантайме.

                                        Угу. Вот именно!
                                        Единственное, что оправдывает такой изврат, так добавившаяся проверка на корректность кода и exception.

                                        Добавлено
                                        Цитата Олег М @
                                        Нужен контроль именно этих констант.

                                        Да, спасибо. Идею понял раньше, из предыдущего комментария. Тем более уже нечто такое делал.

                                        Я сейчас чаи гоняю. До кода ещё не добрался, чтоб попробовать проверку.

                                        Ах да, ваш трюк с именами констант, у меня не сработает, ибо реальные названия разные. Мне ихние встроенные названия не нравятся от слова ообще. А ещё у меня возникает конфликт имён с уже существующими сущностями.
                                          Цитата Eric-S @
                                          Ах да, ваш трюк с именами констант, у меня не сработает, ибо реальные названия разные. Мне ихние встроенные названия не нравятся от слова ообще. А ещё у меня возникает конфликт имён с уже существующими сущностями.


                                          А ты добавь ещё один параметр в ITEM(), своё имя. Тогда сразу будет видно что чему соответствует, и не потребует подключения библиотеки, где не нужно
                                            Цитата Олег М @
                                            А ты добавь ещё один параметр в ITEM(), своё имя. Тогда сразу будет видно что чему соответствует, и не потребует подключения библиотеки, где не нужно

                                            Собственно так и сделал. Решение очевидное. Но всё равно спасибо.

                                            В enum class, значение констант проставил руками. Их всего три, так что не сломался.

                                            А вот в cpp-файле сделал проверку, через макросы со static_assert.

                                            Так же, не стал выкидывать уже существующие функции конвертации. Просто препроцессором отключил runtime switch.
                                            А в альтернативной ветке сделал return static_cast<>()

                                            Вроде всё работает правильно. И даже не слишком страшно.

                                            Единственное, меня лично напрягают проставленные значения констант в enum. Ну да ладно. Они двадцать лет не менялись. Надеюсь, что потом тоже не поменяются.
                                              Это чисто заморочки студийного компилера, gnu c++ от 03 стандарта и далее - не ругается. Проверял.

                                              Вариант ... замени это:

                                              Цитата Eric-S @

                                              ExpandedWrap disabled
                                                class foo
                                                {
                                                public:
                                                static const int alpha;
                                                static const int beta;
                                                };
                                                 
                                                const int foo::alpha = _XXX_SIMBOL_ALPHA;
                                                const int foo::beta = _XXX_SIMBOLBETA;


                                              на это:

                                              ExpandedWrap disabled
                                                namespace foo {
                                                  static const int alpha = _XXX_SIMBOL_ALPHA;
                                                  static const int beta = _XXX_SIMBOLBETA;
                                                };

                                              В остальном работать должно с тем же синтаксисом ... Но на студии я проверить не могу, нет ее у меня.
                                                Цитата JoeUser @

                                                Это чисто заморочки студийного компилера, gnu c++ от 03 стандарта и далее - не ругается. Проверял.


                                                Студия, есть студия. Колемся. Плачем. Но продолжаем есть. Тем более имеются другие плюшки.

                                                Цитата JoeUser @

                                                Вариант ... замени это:


                                                Я уже пошёл иным путём, через enum class и ручного набивания констант.

                                                Цитата JoeUser @

                                                на это...


                                                Фишка того класса была ещё в том, что он исполнял роль обёртки значения. Но я попрощался с ним.

                                                Цитата JoeUser @

                                                В остальном работать должно с тем же синтаксисом ... Но на студии я проверить не могу, нет ее у меня.


                                                Угу. Наверняка будет работать. Спасибо за отклик.
                                                Но фишечка статических полей, как раз была в том, чтоб спрятать значения констант в отдельном файле.
                                                А я похоже, откажусь от всех тех заморочек. Как не крути, а enum class, даёт строгую статическую типизацию. И попутных с ним наворотов кода гораздо меньше.
                                                Сообщение отредактировано: Eric-S -
                                                  Цитата Eric-S @
                                                  Но фишечка статических полей, как раз была в том, чтоб спрятать значения констант в отдельном файле.

                                                  Ну вариантов этого решения - масса. Я не думаю, что это цель.
                                                  Цитата Eric-S @
                                                  даёт строгую статическую типизацию

                                                  А вот это более существенно - что дает ощутимый профит в плане проверок во время сборки. Хотя, скромно вангую) это, имхо, жертва перфекционизму ))) Ошибаться право имею)
                                                    Цитата JoeUser @
                                                    на это:

                                                    Это практически то же самое, что я предложил. Но он фактически хочет, чтобы содержимое хидера можно было бы менять из какого-то модуля. :wacko:

                                                    Добавлено
                                                    Eric-S, уж если тебе так хочется забивать константы в переменные, то откажись от switch, а если параметров много, то заюзай unorderd_map: ощутимой разницы по быстродействию быть не должно. А в целом я бы подлкючил явно заголовочник той либы и не парился.
                                                      Цитата shm @
                                                      Это практически то же самое, что я предложил.

                                                      Практически "да". За исключением того, что инициализация в описании класса стала доступна по синтаксису несколько позже. А нэймспейсы стары как гуано мамонтов)
                                                        Цитата shm @
                                                        а если параметров много, то заюзай unorderd_map: ощутимой разницы по быстродействию быть не должно.

                                                        Речь идёт о двух маленьких группах констант.
                                                        В первом enum у меня всего три пункта.

                                                        Во втором enum их пять.

                                                        И всё! Больше нет констант.

                                                        Добавлено
                                                        Цитата JoeUser @
                                                        А вот это более существенно - что дает ощутимый профит в плане проверок во время сборки. Хотя, скромно вангую) это, имхо, жертва перфекционизму )))

                                                        Она самая. Давно уже стремлюсь к максимальной строгости.
                                                        А те константы меня раздражали, как раз своей нетипизированностью.
                                                        Там, в либе, есть например приблизительно такая функция:
                                                        int set_mode( int x, int y );
                                                        А юмор в том, что в параметр x она просит одну из констант первой группы (всё остальное приводит к ошибке) в runtime). В параметр y просит сочетание флагов из вторых констант. И возвращает тоже некое значение состоящее из флагов второй группы.
                                                        Теперь же получилось очень строго и однозначно.
                                                        group_y set_mode( group_x x, group_y y );
                                                        И хрен кто чего подсунет левого. Только если вооружится static_cast.

                                                        Добавлено
                                                        Цитата shm @
                                                        если тебе так хочется забивать константы в переменные, то откажись от switch

                                                        Так в том-то и дело, что оформляю константу... А компилятор считает её переменной. Я вот и спрашивал, как оформить константу так, чтоб она была именно константой.
                                                          Цитата Eric-S @
                                                          как оформить константу так, чтоб она была именно константой

                                                          constexpr?
                                                            Цитата Алексей_Л @
                                                            Цитата Eric-S @
                                                            как оформить константу так, чтоб она была именно константой

                                                            constexpr?


                                                            Подумал ещё до того, как создавал данную тему. И даже упомянул об этом!

                                                            Цитата Eric-S @
                                                            Проскакивала мысль на счёт constexpr. Но компилятор хочет, чтоб я ему сразу предоставил значение. Чего-то там как-то не так.


                                                            Вообще, у меня constexpr ведёт себя как-то странно. Видимо недаделан.
                                                            Если в функции есть оператор if, то ошибка компиляции.
                                                            Если тело функции в другой единице трансляции, то ошибка линковки.
                                                            Ну и с этим полем static говорит, что его нужно инициализировать!
                                                              Цитата Eric-S @
                                                              Вообще, у меня constexpr ведёт себя как-то странно. Видимо недаделан.
                                                              Если в функции есть оператор if, то ошибка компиляции.

                                                              А не проще сделать, чтоб твои функции, вместо того чтоб возвращать код ошибки выдавали exception? Тогда все эти проблемы просто не возникнут
                                                              Сообщение отредактировано: Олег М -
                                                                Цитата Олег М @
                                                                А не проще сделать, чтоб твои функции, вместо того чтоб возвращать код ошибки выдавали exception? Тогда все эти проблемы просто не возникнут

                                                                Олег, ты о чём? Причём тут код ошибки или исключения? Я писал о constexpr, ошибках компиляции и ошибках линковки.
                                                                Вообще, очень интересно, с чего ты взял, что мои функции возвращают коды ошибок? Может быть, ты меня с кем-то перепутал?
                                                                Сообщение отредактировано: Eric-S -
                                                                  Не знаю. Просто немного потерял нить – зачем это все вообще нужно?
                                                                    Цитата Олег М @
                                                                    Не знаю. Просто немного потерял нить – зачем это все вообще нужно?

                                                                    Сейчас сделал три разных enum.

                                                                    Два из enum используются в качестве битовых флагов, для конфигурирования. Примерно так:
                                                                    ExpandedWrap disabled
                                                                      enum class config { none = 0x0000, alpha = 0x0010, beta = 0x0020, ... };
                                                                       
                                                                      someclass obj0( config::nothing );
                                                                      someclass obj1( config::alpha | config::beta );


                                                                    Для них я перегрузил побитовые операторы.

                                                                    Третий enum используется в нескольких разных местах. В нём лежат идентификаторы.
                                                                    ExpandedWrap disabled
                                                                      enum class msg_category{ first = 0x0000, second = 0x0001, ... };


                                                                    1. для конфигурирования.
                                                                    ExpandedWrap disabled
                                                                      message_handler_guard mhg( msg_category::first, &funcname_proc );


                                                                    2. для отправки сообщений.
                                                                    ExpandedWrap disabled
                                                                      dispatch::send( msg_category::first, "hello, world!" );


                                                                    3. для приёма сообщений
                                                                    ExpandedWrap disabled
                                                                      void funcname_proc( int id, char* message )
                                                                      {
                                                                      switch( static_cast< msg_category >( id ) )
                                                                      {
                                                                       
                                                                      case msg_category::first:
                                                                      cout << message << endl;
                                                                      break;
                                                                       
                                                                      default:
                                                                      throw invalid_message( id );
                                                                       
                                                                      }
                                                                      }


                                                                    У меня только простые классы-обёртки, поверх библиотечных функций.
                                                                    Библиотека использует свои идентификаторы.
                                                                    Переделывать библиотеку не могу и не хочу.
                                                                    Но в итоге, приходится обходится именно с теми константами, которые использует библиотека.
                                                                    Иначе, если придумаю свои константы, библиотека не поймёт пользователя, который работает через мою обёртку, а пользователь не поймёт библиотеку.
                                                                    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                    0 пользователей:


                                                                    Рейтинг@Mail.ru
                                                                    [ Script execution time: 0,0891 ]   [ 17 queries used ]   [ Generated: 23.04.24, 22:49 GMT ]