Здравствуйте, Евгений Музыченко, Вы писали:
S>>А если не повторяются?
ЕМ>Тогда там везде разная логика обработки.
Спасибо, Кэп. Вопрос был не в этом.
ЕМ>И внести ошибку, забыв добавить к сравнению одно из значений, или добавив не то, что нужно, не сложнее, чем сделать опечатку.
Сложнее. Семантическая (да и синтаксическая) нагрузка разная.
S>>вы все никак не можете смириться с той вселенной, в которой живете?
ЕМ>А Вы действительно воображаете, будто это "вселенная", а не просто засилье подхода "делаем потому, что можем"?
Я не воображаю, я это ощущаю как данность: в этой вселенной мы имеем тот C++, который смогли сделать. Хотели разные люди разного, предлагали и рекламировали разное, даже реализовывали в компиляторах в качестве расширений разное. А в итоге имеем то, что имеем. Потому, что другого не смогли.
S>>у вас нужно попросить объяснить, почему спаггети-стайл, и почему в макросах. Если не сможете, то надавать по рукам.
ЕМ>Тут весь вопрос в том, что понимается под "сможете".
То и понимаете: сможете ли объяснить так, что другие члены команды сочтут ваши объяснения достаточными. Или же останетесь на уровне "мне так удобнее".
Хотя о чем это я? Где вы, и где команды.
ЕМ>На принципах применения недоделанных костылей, объединенных не столько разумной логикой, сколько принципами минимализма — "как бы сделать инструмент попроще, чтоб толпа бесплатных энтузиастов придумала для него побольше применений".
А если не бредить общими словами и показать пример? Ну типа вот на макросах, а вот на тех же принципах на шаблонах?
S>>Спич как раз о том, что не нужно требовать от инструмента того, на что он не рассчитан.
ЕМ>То есть, STL, Boost, Loki применяют инструмент именно для того, на что он был рассчитан?
STL, Boost и Loki -- это сами инструменты. И да, они используют базовый C++ именно для того, на что он был рассчитан.
EM>А в последнем обсуждаемом примере одноразовый шаблонный класс создается тоже для того, на что была рассчитана идея классов?
Во-первых, он не одноразовый.
Во-вторых, да, там используется идея шаблона класса.
S>>Тов.B0FEE664 привел пример кода, который решает его задачи. На универсальность не претендует.
ЕМ>Из высказываний тов. B0FEE664 следует как раз обратное.
Цитату можно?
S>>Так чего вы к этому коду прицепились?
ЕМ>Того, что писать такой код поощряет уродливый механизм реализации "современных" возможностей шаблонов, выдаваемый за передовой.
Если вы не смогли этот механизм освоить, то это не значит что:
a) он уродливый;
b) он что-то поощряет или нет;
c) он кем-то выдается за передовой.
Человек сделал так, как ему удобно. Результат понятен. Как пользоваться тоже понятно. Цель, можно сказать, достигнута.
S>>Пишите как можете. C++ позволяет делать одно и тоже кучей разных способов.
ЕМ>Так я всегда пишу, как могу, но C++ постоянно вынуждает делать вроде бы простые вещи непременно через задницу.
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>Вот ввели enum class и что? 90% программистов продолжают прописывать значения элементам и кастить. ЕМ>Теперь это их вина, а не создателей стандартов и компиляторов. У тех, кто имеет доступ к рычагам воздействия, есть выбор — заставлять или не обращать внимания.
Но какой тогда смысл в enum class?
BFE>>Если запретить прописывать значения, то почти все из них просто перестанет пользоваться перечислением. ЕМ>А зачем запрещать-то?
Чтобы не было соблазна их использовать.
ЕМ>Наоборот, от компилятора нужна возможность какой-то работы, отличной от ручной, с набором значений, заданных в пределах отдельного enum, хоть явно, хоть неявно.
Зачем перечислению значения?
Здравствуйте, so5team, Вы писали:
ЕМ>>И внести ошибку, забыв добавить к сравнению одно из значений, или добавив не то, что нужно, не сложнее, чем сделать опечатку.
S>Сложнее. Семантическая (да и синтаксическая) нагрузка разная.
Я уже подчеркивал, что бороться нужно в первую очередь с теми ошибками, которые наиболее вероятны (и в среднем, и в конкретных условиях), а не получили наибольшую известность по тем или иным причинам. Большинство же продолжает опасаться того, о чем больше говорят и пишут, а не того, что наиболее вероятно у них самих.
S>Ну типа вот на макросах, а вот на тех же принципах на шаблонах?
Так приводили ж примеры еще в прошлом году — и на макросах, и на шаблонах. И то, и другое применимо только к частным случаям, в разной мере уродливо, но макросы свыше давно уже объявлены безусловным злом, а шаблоны, даже самые ужасные — безусловным благом.
S>STL, Boost и Loki -- это сами инструменты. И да, они используют базовый C++ именно для того, на что он был рассчитан.
Где можно почитать о том, как в C++ рассчитывали на использование побочных эффектов шаблонов?
EM>>А в последнем обсуждаемом примере одноразовый шаблонный класс создается тоже для того, на что была рассчитана идея классов?
S>Во-первых, он не одноразовый.
В том виде, в каком его применяет автор — одноразовый.
S>Во-вторых, да, там используется идея шаблона класса.
А зачем там класс? По-хорошему, здесь нужен просто шаблон функции.
S>>>Тов.B0FEE664 привел пример кода, который решает его задачи. На универсальность не претендует.
ЕМ>>Из высказываний тов. B0FEE664 следует как раз обратное.
S>Цитату можно?
Я не хочу его осваивать, он вызывает у меня отвращение, поскольку являет собой нагромождение костылей, крайне слабо связанных между собой, с предельно ужатым, и оттого многократно перегруженным синтаксисом. Это не тот случай, когда краткость — сестра таланта.
ЕМ>>C++ постоянно вынуждает делать вроде бы простые вещи непременно через задницу.
S>Без примеров нещитово.
Тут уже кучу примеров навалили, Вам мало? Поскольку Вам они кажутся вполне себе логичными и даже изящными, какой смысл приводить дополнительные?
Знаете, это весьма похоже на "развитие современного искусства". Еще не так давно оставались хоть какие-то опорные точки, позволяющие отличить шедевр от говнища, но теперь все определяется исключительно мнением активного большинства. Даже если численно оно будет абсолютным меньшинством, именно его активность, громкость и упорство позволят признать "шедевром" все, что угодно.
Здравствуйте, B0FEE664, Вы писали:
BFE>какой тогда смысл в enum class?
Прежде всего — в инкапсуляции идентификаторов в enum. А уж как там заданы значения — уже второй вопрос.
Кстати, отсутствие автоматического определения количества элементов, наименьшего и наибольшего значения в enum — тоже очевидный недостаток.
BFE>Зачем перечислению значения?
Для случаев, когда какие-то значения имеют особый смысл. Простейший случай — выделить группы (варианты успешного завершения, предупреждения, ошибки и т.п.). Да, придется закладываться на предельный размер диапазона, но иначе-то еще менее удобно.
Еще в ряде случаев полезно иметь значения, имеющие в младших разрядах уникальные последовательные номера, но с возможным добавлением дополнительных старших разрядов в качестве признаков. Через enum такого не сделать — приходится выписывать пачки обычных определений, вручную следя за монотонным возрастанием номеров. Ежли кто добавит новый элемент в середину, не перенумеровав остальные — будет грустно.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, B0FEE664, Вы писали:
BFE>>какой тогда смысл в enum class? ЕМ>Прежде всего — в инкапсуляции идентификаторов в enum. А уж как там заданы значения — уже второй вопрос. ЕМ>Кстати, отсутствие автоматического определения количества элементов, наименьшего и наибольшего значения в enum — тоже очевидный недостаток.
Так и раньше ни кто не запрещал идентификаторы запихивать внутрь класса вместе с доп. информацией
struct E {
enum { C0,C1,C2, C_MAX };
static const char* to_chars(int id) {
switch(id) {
case C0: return"C0";
case C1: return"C1";
case C2: return"C2";
}
return 0;
}
static int count() { return C_MAX; }
static int min() { return C0; }
static int max() { return C_MAX-1; }
};
struct B {
enum { B1=1,B2=2,B3=4, B_MASK=B1|B2|B3 };
static void fmt(int v, void (*write)(void* ctx,const char* text), void *ctx) {
if (v&B1) write(ctx,"B1");
if (v&B2) write(ctx,"B2");
if (v&B3) write(ctx,"B3");
}
static int mask() { return B_MASK; };
};
ЕМ>Еще в ряде случаев полезно иметь значения, имеющие в младших разрядах уникальные последовательные номера, но с возможным добавлением дополнительных старших разрядов в качестве признаков. Через enum такого не сделать — приходится выписывать пачки обычных определений, вручную следя за монотонным возрастанием номеров. Ежли кто добавит новый элемент в середину, не перенумеровав остальные — будет грустно.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>>И внести ошибку, забыв добавить к сравнению одно из значений, или добавив не то, что нужно, не сложнее, чем сделать опечатку.
S>>Сложнее. Семантическая (да и синтаксическая) нагрузка разная.
ЕМ>Я уже подчеркивал, что бороться нужно в первую очередь с теми ошибками, которые наиболее вероятны (и в среднем, и в конкретных условиях)
Да что вы говорите?!
А тяжесть последствий от ошибки оценивать вообще не нужно?
А стоимость устранения? Например, есть класс ошибок X, стоимость устранения этого класса 1 человеко-час на весь проект. Т.е. даже не копейки, а доли копейки. Полагаю, класс ошибок X нужно вообще не рассматривать, т.к. их вероятность ниже какого-то порога.
Отлично, Евгений, отлично. Жгите. Вы можете, я верю.
ЕМ>Большинство же продолжает опасаться того, о чем больше говорят и пишут, а не того, что наиболее вероятно у них самих.
Какое большинство, актитесь. Вы в одиночку пишете код в который считанные единицы заглядывают. Откуда у вас знания о "большинстве"? Из обсуждений на RSDN-е?
S>>Ну типа вот на макросах, а вот на тех же принципах на шаблонах?
ЕМ>Так приводили ж примеры еще в прошлом году — и на макросах, и на шаблонах. И то, и другое применимо только к частным случаям, в разной мере уродливо, но макросы свыше давно уже объявлены безусловным злом, а шаблоны, даже самые ужасные — безусловным благом.
Т.е. конкретных примеров не будет? Мне нужно перелопачивать все это обсуждение и выискивать примеры самостоятельно?
S>>STL, Boost и Loki -- это сами инструменты. И да, они используют базовый C++ именно для того, на что он был рассчитан.
ЕМ>Где можно почитать о том, как в C++ рассчитывали на использование побочных эффектов шаблонов?
Позволю себе ответить вопросом на вопрос: а что, STL, Boost и Loki базируются на побочных эффектах шаблонов? С примерами, пожалуйста. Это во-первых.
Во-вторых, ну вот есть некие побочные эффекты. Вполне себе легальный способ. Другого нет. Может быть когда-нибудь в будущем что-то будет, может быть нет. Зачем отказываться и не использовать то что есть здесь и сейчас, если это решает задачу наилучшим образом?
У меня есть всего две причины, которые для меня самого временами актуальны:
1) сложность кода превышает способности даже самых опытных и продвинутых членов команды;
2) сложность кода ведет к крахам компиляторов с internal compiler error.
Если эти причины не актуальны, то зачем игнорировать?
Всяко лучше, чем базироваться на нестандартных расширениях от Microsoft.
EM>>>А в последнем обсуждаемом примере одноразовый шаблонный класс создается тоже для того, на что была рассчитана идея классов?
S>>Во-первых, он не одноразовый.
ЕМ>В том виде, в каком его применяет автор — одноразовый.
У вас явно свои представления об "одноразовости". Сам автор привел несколько примеров использования. Если это для вас "одноразовый", то на RSDN-е вам не помогут.
S>>Во-вторых, да, там используется идея шаблона класса.
ЕМ>А зачем там класс? По-хорошему, здесь нужен просто шаблон функции.
Мы не видим всех сценариев использования.
S>>>>Тов.B0FEE664 привел пример кода, который решает его задачи. На универсальность не претендует.
ЕМ>>>Из высказываний тов. B0FEE664 следует как раз обратное.
S>>Цитату можно?
ЕМ>"Для меня этот код не частный, а наоборот, слишком общий...
Ну так перечитайте. Автор пишет, что класс общий, потому, что допускает даже такие сравнения, на которые сам автор не рассчитывал. Универсальности нет, т.к. все сценарии использования в рамках одной и той же задачи -- проверить, входит ли текущее значение в список предопределенных значений.
S>>Если вы не смогли этот механизм освоить
ЕМ>Я не хочу его осваивать, он вызывает у меня отвращение
Да фиолетово что вы хотите. Есть инструмент со своими качествами и возможностями. Этот инструмент можно освоить и применять там, где это выгодно. Либо можно ныть на RSDN-е о том, как вокруг все коряво и убого.
ЕМ>>>C++ постоянно вынуждает делать вроде бы простые вещи непременно через задницу.
S>>Без примеров нещитово.
ЕМ>Тут уже кучу примеров навалили, Вам мало? Поскольку Вам они кажутся вполне себе логичными и даже изящными, какой смысл приводить дополнительные?
Можете привести пример и сказать "вот здесь плохо потому-то и потому-то?"
Если можете, тогда будет что обсуждать.
Но вряд ли сможете. Ведь это же в предмете придется разбираться, а не уходить в аналогии про современное искусство.
ЕМ>Знаете, это весьма похоже на "развитие современного искусства".
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>какой тогда смысл в enum class? ЕМ>Прежде всего — в инкапсуляции идентификаторов в enum. А уж как там заданы значения — уже второй вопрос.
ЕМ>Кстати, отсутствие автоматического определения количества элементов, наименьшего и наибольшего значения в enum — тоже очевидный недостаток.
Вроде бы (ещё не дочитал), это собираются, наконец, сделать.
BFE>>Зачем перечислению значения? ЕМ>Для случаев, когда какие-то значения имеют особый смысл. Простейший случай — выделить группы (варианты успешного завершения, предупреждения, ошибки и т.п.). Да, придется закладываться на предельный размер диапазона, но иначе-то еще менее удобно.
Что ещё за "предельный размер диапазона"?
ЕМ>Еще в ряде случаев полезно иметь значения, имеющие в младших разрядах уникальные последовательные номера, но с возможным добавлением дополнительных старших разрядов в качестве признаков. Через enum такого не сделать — приходится выписывать пачки обычных определений, вручную следя за монотонным возрастанием номеров. Ежли кто добавит новый элемент в середину, не перенумеровав остальные — будет грустно.
Пожалуйста, ответьте не на вопрос: какое отношение это имеет к перечислению?
Здравствуйте, B0FEE664, Вы писали:
ЕМ>>Прежде всего — в инкапсуляции идентификаторов в enum. BFE>
BFE>namespace Machine
BFE>enum Mode
BFE>
Ну коряво же. Давайте еще вспомним, что в раннем C имена полей структур тоже были глобальными, и починили это чуть ли не после появления C++. Может, Страуструпу не нужно было ограничивать область видимости членов класса, нехай бы все были в глобальной?
BFE>Что ещё за "предельный размер диапазона"?
Когда в enum определяется несколько групп констант, в каждой группе значения идут подряд, но между группами делаются промежутки на случай добавления новых значений.
BFE>какое отношение это имеет к перечислению?
Прямое. Перечисление лежит в основе создания констант, а явное задание значений позволяет в отдельных случаях отступать от этого порядка. Если [почти] все константы имеют явно заданные значения, то и не стоит их определять в enum.
Если бы enum изначально был похож на паскалевский перечислимый тип, давал возможность узнавать количество элементов и создавать множества, я бы не стал требовать от него явного задания значений. Но раз уж его реализовали в виде примитивного средства с дополнительными возможностями, то грех не пользоваться.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>>Прежде всего — в инкапсуляции идентификаторов в enum. BFE>>
BFE>>namespace Machine
BFE>>enum Mode
BFE>>
ЕМ>Ну коряво же.
Почему?
ЕМ>Давайте еще вспомним, что в раннем C имена полей структур тоже были глобальными, и починили это чуть ли не после появления C++. Может, Страуструпу не нужно было ограничивать область видимости членов класса, нехай бы все были в глобальной?
Давайте. Что делать, если в двух библиотеках совпадают названия (но не элементы) у enum class?
BFE>>какое отношение это имеет к перечислению? ЕМ>Прямое. Перечисление лежит в основе создания констант, а явное задание значений позволяет в отдельных случаях отступать от этого порядка. Если [почти] все константы имеют явно заданные значения, то и не стоит их определять в enum.
Вообще-то в основе создания констант лежит #define
ЕМ>Если бы enum изначально был похож на паскалевский перечислимый тип, давал возможность узнавать количество элементов и создавать множества, я бы не стал требовать от него явного задания значений.
Судя по предыдущему абзацу и улыбке — стали бы.
ЕМ> Но раз уж его реализовали в виде примитивного средства с дополнительными возможностями, то грех не пользоваться.
То есть использовать перечисления для констант — это не грех (несмотря на то, что ключевое слово const существует довольно давно), а использовать SFINAE — грех? Не находите, что это не последовательная позиция?
Здравствуйте, B0FEE664, Вы писали:
BFE>То есть использовать перечисления для констант — это не грех (несмотря на то, что ключевое слово const существует довольно давно), а использовать SFINAE — грех? Не находите, что это не последовательная позиция?
Ваш const не совсем const, поэтому и используют другие способы
int fn(int i) {
const int c1=1;
enum { c2=2 };
switch(i) {
//case c1: return c1; // error: label does not reduce to an integer constantcase c2: return c2;
}
return 0;
}
Здравствуйте, B0FEE664, Вы писали:
ЕМ>>Ну коряво же. BFE>Почему?
Потому, что enum создает группу идентификаторов, объединенных общей идеей, а следовательно — областью видимости, пусть и неявной. Никто ж не создает {One, Two, Three}. Почему в обсуждаемом примере все идентификаторы начинаются на E?
BFE>Что делать, если в двух библиотеках совпадают названия (но не элементы) у enum class?
То же самое, как если совпадают имена классов, глобальных переменных, функций. Почему enum должен выбиваться из этой схемы?
BFE>Вообще-то в основе создания констант лежит #define
Вообще-то это не "константы", а "макроопределения". Это делалось (и посейчас нередко делается) исключительно от нехватки языковых средств.
BFE>То есть использовать перечисления для констант — это не грех (несмотря на то, что ключевое слово const существует довольно давно)
Когда const только появилось, большинство компиляторов понимало его исключительно в смысле "неизменяемый объект", и даже при максимальной оптимизации не всегда заменяло на литеральную константу. Заменять всегда стали лишь где-то в середине 90-х, если не ошибаюсь.
BFE>использовать SFINAE — грех?
Конечно, использовать SFINAE для выбора наиболее общего варианта шаблона — не грех, оно для этого и создавалось. И даже использовать SFINAE в сочетании с трюками, возможность которых изначально не закладывалась в механизм — тоже не грех, если это делается или для демонстрации забавного эффекта, или сугубо для себя, или сугубо временно, в ожидании реализации соответствующих функций в компиляторах. А вот делать такие трюки нормой жизни, да еще рекомендовать их для изучения, освоения и повсеместного применения — не простой грех, а очень тяжкий. Подход называется "ну ведь получилось же, и работает, какие претензии?".
Здравствуйте, kov_serg, Вы писали:
BFE>>То есть использовать перечисления для констант — это не грех (несмотря на то, что ключевое слово const существует довольно давно), а использовать SFINAE — грех? Не находите, что это не последовательная позиция? _>Ваш const не совсем const, поэтому и используют другие способы
А он не мой, это не я стандарт писал.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>>>Ну коряво же. BFE>>Почему? ЕМ>Потому, что enum создает группу идентификаторов, объединенных общей идеей, а следовательно — областью видимости, пусть и неявной. Никто ж не создает {One, Two, Three}.
И для этого они лежат в namespace.
ЕМ> Почему в обсуждаемом примере все идентификаторы начинаются на E?
Предполагаю, что это сокращение от слова ERROR.
BFE>>Что делать, если в двух библиотеках совпадают названия (но не элементы) у enum class? ЕМ>То же самое, как если совпадают имена классов, глобальных переменных, функций. Почему enum должен выбиваться из этой схемы?
Вот если их поместить в отдельный namespace, то они и не будут выбиваться из схемы (раз уж изначально это не было сделано)
BFE>>Вообще-то в основе создания констант лежит #define ЕМ>Вообще-то это не "константы", а "макроопределения". Это делалось (и посейчас нередко делается) исключительно от нехватки языковых средств.
Согласен. Но это никак не отменяет, что использовать #define для констант уместнее, чем enum.
BFE>>использовать SFINAE — грех? ЕМ>Конечно, использовать SFINAE для выбора наиболее общего варианта шаблона — не грех, оно для этого и создавалось. И даже использовать SFINAE в сочетании с трюками, возможность которых изначально не закладывалась в механизм — тоже не грех, если это делается или для демонстрации забавного эффекта, или сугубо для себя, или сугубо временно, в ожидании реализации соответствующих функций в компиляторах. А вот делать такие трюки нормой жизни, да еще рекомендовать их для изучения, освоения и повсеместного применения — не простой грех, а очень тяжкий. Подход называется "ну ведь получилось же, и работает, какие претензии?".
Вот сейчас уже есть нормальные константы. Вы перестали использовать перечисления для того, чтобы задавать константы?
Здравствуйте, B0FEE664, Вы писали:
ЕМ>>Потому, что enum создает группу идентификаторов, объединенных общей идеей
BFE>И для этого они лежат в namespace.
Тогда почему там не лежат члены классов?
ЕМ>>Почему в обсуждаемом примере все идентификаторы начинаются на E?
BFE>Предполагаю, что это сокращение от слова ERROR.
А зачем нужен такой префикс? Уникальность обеспечивается и без него.
BFE>Вот если их поместить в отдельный namespace, то они и не будут выбиваться из схемы (раз уж изначально это не было сделано)
Изначально, напомню, инкапсуляции не было и для полей структур. Ее тоже зря сделали?
BFE>использовать #define для констант уместнее, чем enum.
Я бы сказал, что уместнее использовать [static] const, а при невозможности — #define. Но это для разрозненных констант, от которых не ожидается какой-либо регулярности. Если же константы хотя бы в основе завязаны на перечисление, то вполне логично определять их в перечислении.
BFE>Вот сейчас уже есть нормальные константы. Вы перестали использовать перечисления для того, чтобы задавать константы?
Я ж говорил, что для "просто констант" давно использую [static] const. Но, если мне нужны константы, например, для кодов ошибок, разделенных на группы (по степени серьезности, или по ситуациям, по связанным объектам и т.п.), то альтернативой enum будет только ручной инкремент. Вы предлагаете использовать его?
Если Вы до сих пор пытаетесь провести аналогию с шаблонными трюками, то это ж несопоставимые вещи. enum — простая конструкция, ее смысл очевиден любому, кто хоть более-менее знаком с языком. Она не порождает отдаленных последствий. Ну и то, что в языке таки появился enum class, уже говорит о том, что проблему осознали, и приняли меры для ее устранения. А что появилось в языке для замены шаблонной магии? Даже if constexpr можно применить только к исполняемому коду. Это не метапрограммирование, а издевательство.
А теперь представьте что константы надо объявить в header-е
extern const int a;
const int b=1;
const int a=0;
И всё приплыли. А enum-ы можно объявлять где попало и они constexpr. Правда использование таких констант в шаблонах немного не удобно. Но это проблемы шаблонов, а не констант.
Здравствуйте, Евгений Музыченко, Вы писали: ЕМ>>>Потому, что enum создает группу идентификаторов, объединенных общей идеей BFE>>И для этого они лежат в namespace. ЕМ>Тогда почему там не лежат члены классов?
Потому, что их объединение производится через class ЕМ>>>Почему в обсуждаемом примере все идентификаторы начинаются на E? BFE>>Предполагаю, что это сокращение от слова ERROR. ЕМ>А зачем нужен такой префикс?
Чтобы показать, что всё это коды ошибок. ЕМ>Уникальность обеспечивается и без него.
Ни с префиксом, ни без префикса уникальность не обеспечивается. BFE>>Вот если их поместить в отдельный namespace, то они и не будут выбиваться из схемы (раз уж изначально это не было сделано) ЕМ>Изначально, напомню, инкапсуляции не было и для полей структур. Ее тоже зря сделали?
Наоборот, делали не зря. Зря не сделали этого с enum и зря перечислениям не запретили присваивать численные значения. BFE>>использовать #define для констант уместнее, чем enum. ЕМ>Я бы сказал, что уместнее использовать [static] const, а при невозможности — #define. Но это для разрозненных констант, от которых не ожидается какой-либо регулярности. Если же константы хотя бы в основе завязаны на перечисление, то вполне логично определять их в перечислении.
Нет, не логично. Константы логично объединить в множество или положить в одно scope-пространство, но не в перечисление. BFE>>Вот сейчас уже есть нормальные константы. Вы перестали использовать перечисления для того, чтобы задавать константы? ЕМ>Я ж говорил, что для "просто констант" давно использую [static] const.
Почему не constexp ?
Скрытый текст
#include <iostream>
#include <stdexcept>
constexpr int next(int n) { return 1 + n; }
constexpr int asdf = 1;
constexpr int asdg = next(asdf);
int main()
{
std::cout << '\n';
std::cout << "asdf = " << asdf;
std::cout << '\n';
std::cout << "asdg = " << asdg;
constexpr int arr[asdg] = {asdf, asdg};
int x = 2;
switch(x)
{
case arr[0]:
std::cout << '\n' << "arr[0] ";
break;
case arr[1]:
std::cout << '\n' << "arr[1]";
break;
}
}
ЕМ>Но, если мне нужны константы, например, для кодов ошибок, разделенных на группы (по степени серьезности, или по ситуациям, по связанным объектам и т.п.), то альтернативой enum будет только ручной инкремент. Вы предлагаете использовать его?
Можно и инкремент, если он вам зачем-то нужен, хотя я с трудом представляю ситуацию, где ТАКОЕ может понадобиться.
Я вообще не понимаю, зачем использовать коды ошибок. У ошибки есть имя — этого достаточно. А код — он может меняться от системы к системе, ну, как в исходном примере, с EAGAIN и EWOULDBLOCK.
Именно поэтому я для ошибок часто использую перечисления и никогда константы. И перечисления я использую именно как перечисления, то есть набор имен и никак не значений. ЕМ>Если Вы до сих пор пытаетесь провести аналогию с шаблонными трюками, то это ж несопоставимые вещи.
Для меня это то же самое — использование конструкции языка не по назначению. ЕМ>enum — простая конструкция, ее смысл очевиден любому, кто хоть более-менее знаком с языком. Она не порождает отдаленных последствий.
Да ну? Любому? Да 90% вообще не понимают (включая авторов стандарта), что такое перечисление и вы, похоже, из их числа, раз путаете перечисление с набором констант.
И вообще, попробуйте поспрашивать коллег, что выведет следующий код:
#include <iostream>
enum AB
{
a = 1,
b = 0xF0000000
};
enum CD
{
cd_c = 1,
cd_d = 0xF00000000
};
int main()
{
if ( sizeof(a) == sizeof(cd_c) )
std::cout << "yes";
else
std::cout << "no";
}
ЕМ> Ну и то, что в языке таки появился enum class, уже говорит о том, что проблему осознали, и приняли меры для ее устранения.
Нет, не осознали. Даже наоборот: они ввели std::byte. ЕМ> А что появилось в языке для замены шаблонной магии?
auto ЕМ> Даже if constexpr можно применить только к исполняемому коду. Это не метапрограммирование, а издевательство.
Метапрограммирование ещё только предлагают, но какое-то некрасивое.
Здравствуйте, B0FEE664, Вы писали:
ЕМ>>Тогда почему там не лежат члены классов?
BFE>Потому, что их объединение производится через class
Чем это принципиально отличается от объединения через enum?
ЕМ>>А зачем нужен такой префикс?
BFE>Чтобы показать, что всё это коды ошибок.
На букву E могут начинаться не только идентификаторы кодов ошибок. А если полагать, что идентификатор в верхнем регистре, начинающийся на E — это код ошибки, то что это, если не обособленная группа?
ЕМ>>Уникальность обеспечивается и без него.
BFE>Ни с префиксом, ни без префикса уникальность не обеспечивается.
Я про "локальную уникальность" среди кодов ошибок вида Exxx. Будь enum изначально инкапсулирующий, можно было сразу определить вроде enum ErrorCode { ... };
BFE>зря перечислениям не запретили присваивать численные значения.
Какие неудобства или риски это создает?
Ситуация, кстати, похожа на ту самую подстановку пакета параметров шаблона. Сейчас это возможно только в регулярном, систематическом виде. Если вдруг нужен пакет разнотипных параметров, то или никак, или через вырвиглазные трюки. А будь внутри шаблона возможность работать параметрами по отдельности, так и систематически, это можно было бы применить к более широкому спектру задач.
Так и с enum: его можно применить для создания только систематических, регулярных перечислений, а можно в эту регулярность при необходимости вмешаться. А если б вмешиваться можно было по-разному, объясняя компилятору, как сочетать регулярность с отступлениями от нее, не приходилось бы городить костыли.
BFE>Константы логично объединить в множество или положить в одно scope-пространство, но не в перечисление.
А если во множестве несколько сотен констант, 95% из которых идут подряд, но 5% этот порядок нарушают?
ЕМ>>Я ж говорил, что для "просто констант" давно использую [static] const. BFE>Почему не constexp ?
Потому, что после VS 2008 я еще не видел столь же удобной и быстрой в работе версии, а компиляторы VS 2008 constexpr еще не знают.
ЕМ>>Но, если мне нужны константы, например, для кодов ошибок, разделенных на группы (по степени серьезности, или по ситуациям, по связанным объектам и т.п.), то альтернативой enum будет только ручной инкремент. Вы предлагаете использовать его?
BFE>Можно и инкремент, если он вам зачем-то нужен, хотя я с трудом представляю ситуацию, где ТАКОЕ может понадобиться.
Ну вот, например, коды оконных сообщений в винде в целом идут подряд, но разбиты на группы.
BFE>Я вообще не понимаю, зачем использовать коды ошибок. У ошибки есть имя — этого достаточно.
У ошибки также могут быть и свойства — уровень серьезности, область возникновения и т.п. Например, в виндовом ядре и Win32 32-разрядный код ошибки содержит несколько полей.
BFE>А код — он может меняться от системы к системе, ну, как в исходном примере, с EAGAIN и EWOULDBLOCK.
Да, и это создает приличный геморрой в линуксах, как и необходимость во многих случаях собирать софт под целевую систему. А в винде коды не меняются, они всегда одни и те же в любой системе на базе Win32. И приложение, правильно сделанное под Win95, будет в неизменном виде работать под Win11. На мой взгляд, это более серьезная степень совместимости, нежели на уровне исходников.
BFE>Именно поэтому я для ошибок часто использую перечисления и никогда константы. И перечисления я использую именно как перечисления, то есть набор имен и никак не значений.
В идеальном перечислении было бы удобно иметь возможность задавать правила присвоения значений константам. Тогда можно было бы выбирать как простое перечисление, так и более сложное, но все равно систематическое. То же самое можно было бы сделать, будь в языке макропроцессор с псевдоциклами. Без этого какие-то варианты можно реализовать только шаблонными трюками.
BFE>Для меня это то же самое — использование конструкции языка не по назначению.
Что значит "не по назначению"? Для enum изначально была заявлена возможность явного задания значений, а возможность шаблонных трюков была открыта случайно.
BFE>Да 90% вообще не понимают (включая авторов стандарта), что такое перечисление и вы, похоже, из их числа, раз путаете перечисление с набором констант.
И что же такое перечисление? А главное — из чего следует именно такая его природа, а не иная?
BFE>
BFE> cd_d = 0xF00000000
BFE>
Как раз тот случай, когда максимальный уровень предупреждений чертовски полезен.
BFE>они ввели std::byte.
Ну, не слишком удачная попытка разгрузить char. Так-то, есть действительно что-то неправильное в том, что строковый тип смешан с числовым. По-хорошему, еще в C имело смысл сделать отдельно тип byte, и отдельно — char.
ЕМ>> А что появилось в языке для замены шаблонной магии?
BFE>auto
Что, прям всей?
BFE>Метапрограммирование ещё только предлагают, но какое-то некрасивое.
Пару десятков лет так делаю и полет (для примитивных типов) нормальный.
_>
_>extern const int a;
_>
А не надо в C++ тянуть привычки из чистого Си.
_>И всё приплыли.
Отучаемся говорить за всех (c)
До появления constexpr и inline const были проблемы с декларацией в хидерах констант сложных типов, вроде std::string или std::vector. Но это уже совсем другая история.
_>А enum-ы можно объявлять где попало и они constexpr.
До C++11 enum-ы были единственным нормальным способом объявлять константы в метапрограммировании, т.к. в C++98 можно было так: