Здравствуйте, so5team, Вы писали:
S>До C++11 enum-ы были единственным нормальным способом объявлять константы в метапрограммировании, т.к. в C++98 можно было так: S>
Здравствуйте, so5team, Вы писали:
S>До появления constexpr и inline const были проблемы с декларацией в хидерах констант сложных типов, вроде std::string или std::vector. Но это уже совсем другая история.
Мне нафиг не нужны сложные типы. Мне просто числовые константы нужны. Например хеш коды строк
Лучше бы сделали возможноcть явно указывать какие модули будут использоваться и их надо линковать, и указывать как статически или динамически, разместив их в отдельном файле.
Image::register_plugin(jpg);
Image::register_plugin(png);
Image::register_plugin(gif);
Image::register_plugin(webm);
...
auto image=Image::load(filename);
Здравствуйте, kov_serg, Вы писали:
S>>Общение с вами заставило вспомнить народную мудрость: не тронь говно, вонять не будет.
_>Лучше бы вспомнили: Будьте проще и работает — не трогай
В случае простых enum-ов оно не работает для типов, отличных от int.
В случае enum class оно не работает для типов, отличных от целочисленных, да еще и требует указывать дополнительный скоуп.
В общем, оно не работает. А я опять вляпался в известную субстанцию в попытках объяснить персонажам вроде вас очевидные вещи
Здравствуйте, Евгений Музыченко, Вы писали: ЕМ>>>Тогда почему там не лежат члены классов? BFE>>Потому, что их объединение производится через class ЕМ>Чем это принципиально отличается от объединения через enum?
Ничем. Элементы перечисления тоже не должны были бы видимы прямо из глобального пространства. ЕМ>>>А зачем нужен такой префикс? BFE>>Чтобы показать, что всё это коды ошибок. ЕМ>На букву E могут начинаться не только идентификаторы кодов ошибок. А если полагать, что идентификатор в верхнем регистре, начинающийся на E — это код ошибки, то что это, если не обособленная группа?
Её обособленность никак не выражена средствами языка. ЕМ>>>Уникальность обеспечивается и без него. BFE>>Ни с префиксом, ни без префикса уникальность не обеспечивается. ЕМ>Я про "локальную уникальность" среди кодов ошибок вида Exxx. Будь enum изначально инкапсулирующий, можно было сразу определить вроде enum ErrorCode { ... };
Ну было бы пересечение по имени ErrorCode BFE>>зря перечислениям не запретили присваивать численные значения. ЕМ>Какие неудобства или риски это создает?
Я их не раз уже перечислял. Повторю. Добавление нового элемента в середину перечисления приводит к просмотру и правке всего кода, который прямо или косвенно связан с константами. Изменение значения элемента перечисления приводит просмотру и правке всего кода, который прямо или косвенно связан с перечислением. ЕМ>Ситуация, кстати, похожа на ту самую подстановку пакета параметров шаблона. Сейчас это возможно только в регулярном, систематическом виде. Если вдруг нужен пакет разнотипных параметров, то или никак, или через вырвиглазные трюки.
Ерунду пишите. Нет тут ничего вырвиглазного:
ЕМ>А будь внутри шаблона возможность работать параметрами по отдельности, так и систематически, это можно было бы применить к более широкому спектру задач.
Сомневаюсь, что такое вообще возможно без рантайм информации о типе. Убеждён, что если же вам нужна рантайм информации о типе, значит вы что-то не понимаете в программировании на C++. ЕМ>Так и с enum: его можно применить для создания только систематических, регулярных перечислений, а можно в эту регулярность при необходимости вмешаться. А если б вмешиваться можно было по-разному, объясняя компилятору, как сочетать регулярность с отступлениями от нее, не приходилось бы городить костыли.
То, что вы понимаете под регулярностью, я считаю вообще не должно быть в языке и является вредным излишеством. BFE>>Константы логично объединить в множество или положить в одно scope-пространство, но не в перечисление. ЕМ>А если во множестве несколько сотен констант, 95% из которых идут подряд, но 5% этот порядок нарушают?
Всего несколько сотен? Вот реально мне не сложно было бы их прописать так, как я уже это делал выше:
constexpr int next(int n) { return 1 + n; }
constexpr int a = 1;
constexpr int b = next(a);
constexpr int c = next(b);
constexpr int d = c + 123;
constexpr int e = next(d);
ЕМ>>>Я ж говорил, что для "просто констант" давно использую [static] const. BFE>>Почему не constexp ? ЕМ>Потому, что после VS 2008 я еще не видел столь же удобной и быстрой в работе версии, а компиляторы VS 2008 constexpr еще не знают.
Если мне не изменяет память VS 2008 можно сконфигурировать с новыми компиляторами. ЕМ>>>Но, если мне нужны константы, например, для кодов ошибок, разделенных на группы (по степени серьезности, или по ситуациям, по связанным объектам и т.п.), то альтернативой enum будет только ручной инкремент. Вы предлагаете использовать его?
Нет, я предлагаю вообще не полагаться на численные значения для ошибок.
Но если вам они зачем-то, таки, нужны, то — да, только ручной инкремент, как в примере выше. BFE>>Можно и инкремент, если он вам зачем-то нужен, хотя я с трудом представляю ситуацию, где ТАКОЕ может понадобиться. ЕМ>Ну вот, например, коды оконных сообщений в винде в целом идут подряд, но разбиты на группы.
И зачем закладываться на их числовые значения? Я не уверен, кстати, что кто-то так делает... BFE>>Я вообще не понимаю, зачем использовать коды ошибок. У ошибки есть имя — этого достаточно. ЕМ>У ошибки также могут быть и свойства — уровень серьезности, область возникновения и т.п.
Может, конечно. Только для определения уровень серьезности, область возникновения и т.п. числовое значение не обязательно. ЕМ>Например, в виндовом ядре и Win32 32-разрядный код ошибки содержит несколько полей.
Да, но его текстовое описание, например, всё равно лежит отдельно. BFE>>А код — он может меняться от системы к системе, ну, как в исходном примере, с EAGAIN и EWOULDBLOCK. ЕМ>Да, и это создает приличный геморрой в линуксах, как и необходимость во многих случаях собирать софт под целевую систему.
Обычно, если читать документацию и думать головой — то никаких проблем с этим нет. ЕМ>А в винде коды не меняются, они всегда одни и те же в любой системе на базе Win32.
А вот из-за этого, да — неприличный "геморрой". Пример ниже. ЕМ>И приложение, правильно сделанное под Win95, будет в неизменном виде работать под Win11. На мой взгляд, это более серьезная степень совместимости, нежели на уровне исходников.
Не будут. Стоит только указать путь до файла достаточно длинный, как всё поломается. Причём чаше всего ломается достаточно быстро, 261 символ и всё — приплыли. А почему? Из-за неизменной константы. BFE>>Именно поэтому я для ошибок часто использую перечисления и никогда константы. И перечисления я использую именно как перечисления, то есть набор имен и никак не значений. ЕМ>В идеальном перечислении было бы удобно иметь возможность задавать правила присвоения значений константам. Тогда можно было бы выбирать как простое перечисление, так и более сложное, но все равно систематическое. То же самое можно было бы сделать, будь в языке макропроцессор с псевдоциклами. Без этого какие-то варианты можно реализовать только шаблонными трюками.
Ничего подобного. Перечисление — оно на то и перечисление, что само значений не хранит. А вот автоматическое сопоставление различных значений различных типов элементам перечислений было бы удобно и его реально не хватает. BFE>>Для меня это то же самое — использование конструкции языка не по назначению. ЕМ>Что значит "не по назначению"? Для enum изначально была заявлена возможность явного задания значений, а возможность шаблонных трюков была открыта случайно.
Значит, что в нормальных перечислениях одному элементу перечисления может быть сопоставлено несколько разных значений. А то, что в С++ в enum изначально была заявлена возможность явного задания значений — это от бедности и концептуально ошибочно. BFE>>Да 90% вообще не понимают (включая авторов стандарта), что такое перечисление и вы, похоже, из их числа, раз путаете перечисление с набором констант. ЕМ>И что же такое перечисление? А главное — из чего следует именно такая его природа, а не иная?
Перечисление — это то, что можно перечислить.
Перечисляемый тип (сокращённо перечисле́ние, англ. enumeration, enumerated type) — в программировании тип данных, чьё множество значений представляет собой ограниченный список идентификаторов.
Элементу перечисления можно сопоставить некоторые значения и сделать это можно различными способами. Другое дело, что делать сопоставление руками чревато ошибками. BFE>>
BFE>> cd_d = 0xF00000000
BFE>>
ЕМ>Как раз тот случай, когда максимальный уровень предупреждений чертовски полезен.
Это как раз тот случай, когда изменение значения enum порождает отдалённые последствия. ЕМ>>> А что появилось в языке для замены шаблонной магии? BFE>>auto ЕМ>Что, прям всей?
Если вам не нужна шаблонная магия, то не используйте её. BFE>>Метапрограммирование ещё только предлагают, но какое-то некрасивое. ЕМ>Какое метапрограммирование Вы сочли бы красивым?
Это сложный вопрос, я не готов на него ответить.
Здравствуйте, B0FEE664, Вы писали:
BFE>Элементы перечисления тоже не должны были бы видимы прямо из глобального пространства.
Что-то я запутался. Когда я Вам приводил enum class в качестве примера разумного прогресса в языке, Вы ответили в том смысле, что "не очень-то и хотелось", поскольку enum можно было завернуть в namespace.
BFE>Её обособленность никак не выражена средствами языка.
Ну так и я о том же. Изначально (еще с C) ущербная реализация enum породила эту порочную практику с префиксами. Возможно, на такую реализацию пошли сознательно, чтоб предельно упростить компилятор. Но потом-то, когда добавили инкапсуляцию полей структур, было самое время добавить ее и к enum, предусмотрев режим обратной совместимости для извращенцев и ретроградов. Но предпочли тянуть аж двадцать лет, куда это годится?
BFE>Ну было бы пересечение по имени ErrorCode
И "увидели бы они, что это хорошо".
BFE>Добавление нового элемента в середину перечисления приводит к просмотру и правке всего кода, который прямо или косвенно связан с константами. Изменение значения элемента перечисления приводит просмотру и правке всего кода, который прямо или косвенно связан с перечислением.
И Вас не смущает, что код, требующий такого пересмотра, фундаментально ущербен? Если код определяет "просто перечисление", то он не имеет оснований закладываться ни на количество элементов, ни на их значения — только на то, что они будут уникальными в пределах перечисления, и возрастать монотонно. Вы еще посетуйте, что код, закладывающийся на порядок следования данных-членов класса, их смещения и размеры, ломается при вставке новых членов в середину.
Если код таки закладывается на значения элементов и/или соотношения между ними, то нужно или принимать меры, которые я упоминал выше (например, добавлять элементы вида Group1_First, Group1_Last, Group2_First, Group2_Last и т.п.), или определять эти значения явно (против чего вы почему-то активно выступаете). На самый худющий конец — обернуть этот enum огромнейшим комментарием, обещающим ужасные кары тому, кто осмелится его менять неподобающим образом, и вдобавок наставить assert'ов, проверяющих соотношения.
ЕМ>>Если вдруг нужен пакет разнотипных параметров, то или никак, или через вырвиглазные трюки.
BFE>Ерунду пишите. Нет тут ничего вырвиглазного:
А сможете этот пакет разобрать поштучно непосредственно в шаблоне, чтобы, в зависимости от типов, породить произвольный код, и чтоб это не выглядело похожим на традиционное "char* (*(*foo[5])(char*))[];", которым только детей пугать?
BFE>Сомневаюсь, что такое вообще возможно без рантайм информации о типе.
Зачем здесь рантайм? Я говорю исключительно о времени компиляции. Чтоб в шаблоне можно было как обращаться к его параметрам по индексам, так и записать конструкцию псевдоцикла, перебирающего параметры, узнающего у компилятора свойства фактических параметров, чтоб в итоге порождать код в зависимости от любых необходимых условий.
То есть, чтоб шаблон работал подобно обычной функции, работающей со своими фактическими параметрами через имена формальных, но вместо выполнения операторов порождал код для последующей компиляции, как это делает любой адекватный макропроцессор.
BFE>Убеждён, что если же вам нужна рантайм информации о типе, значит вы что-то не понимаете в программировании на C++.
А если я что-то понимаю, но информация мне все равно нужна? Например, в сугубо отладочных целях?
BFE>То, что вы понимаете под регулярностью, я считаю вообще не должно быть в языке и является вредным излишеством.
Я опять запутался. Решения, которые Вы делаете с помощью пакетов параметров, основаны на этой самой регулярности: Вы указываете только базовую схему подстановки, а компилятор разворачивает ее, единообразно подставляя каждый параметр пакета. Или Вы этого тоже не одобряете, и используете лишь от безысходности?
Из Вашего утверждения также следует, что массивы в языке тоже являются вредным излишеством. Ну, или Вы меня неправильно поняли.
BFE>мне не сложно было бы их прописать так, как я уже это делал выше: BFE>
BFE>constexpr int b = next(a);
BFE>constexpr int c = next(b);
BFE>
Во-первых, даже для десятка-другого это будет чрезмерно громоздко (а следовательно, менее понятно и наглядно) по сравнению с enum. Во-вторых, большинство имен придется указывать в двух местах, а это влечет за собой известную проблему согласованности, но средств автоматизированного обеспечения согласованности у нас нет. Я не вижу в таком способе ни одного преимущества перед enum, но вижу серьезные недостатки.
BFE>Если мне не изменяет память VS 2008 можно сконфигурировать с новыми компиляторами.
Штатно — нельзя. У нее все свойства платформы забиты в двоичные файлы конфигурации, их только хачить. Ну, или делать самодельные переходники для cl.exe/link.exe, которые будут запускать новые версии, попутно правя командные строки, поскольку в VS 2005/2008 некоторые ключи вставляются всегда, а новые компиляторы на них ругаются.
BFE>я предлагаю вообще не полагаться на численные значения для ошибок.
В смысле, на конкретные численные значения? Для этого достаточно даже простого перечисления имен в enum, а если нам нужно знать о них что-то большее, то конкретные значения появляются только в одном месте, во всех остальных используются только имена. То есть, на конкретные значения никто не полагается — в точке определения их можно менять, и нигде ничего не поломается.
BFE>Но если вам они зачем-то, таки, нужны, то — да, только ручной инкремент
Ей-богу, не понимаю, почему "только ручной", когда язык предоставляет автоматический.
ЕМ>>например, коды оконных сообщений в винде в целом идут подряд, но разбиты на группы.
BFE>И зачем закладываться на их числовые значения? Я не уверен, кстати, что кто-то так делает...
Никто и не делает — все пользуются именами. Имена, кстати, определены литерально — через #define, чтоб гарантировать одинаковые значения во всех системах. Но для себя я не вижу причин отказываться от enum, ибо это его изначальная, штатная функция.
BFE>для определения уровень серьезности, область возникновения и т.п. числовое значение не обязательно.
Если Вы о том, чтобы завернуть все это в объект, то такое не прокатит в глобальном масштабе. Если ОС будет предоставлять интерфейс на продвинутом C++, разработчики других языков замучатся их сопрягать. Они и с традиционным сишным не всегда могут сопрячь.
А у себя-то, в пределах своего продукта, вполне себе можно.
ЕМ>>Например, в виндовом ядре и Win32 32-разрядный код ошибки содержит несколько полей. BFE>Да, но его текстовое описание, например, всё равно лежит отдельно.
Да, это недостаток. Но, увы, пока неустранимый.
ЕМ>>И приложение, правильно сделанное под Win95, будет в неизменном виде работать под Win11.
BFE>Не будут. Стоит только указать путь до файла достаточно длинный, как всё поломается. Причём чаше всего ломается достаточно быстро, 261 символ и всё — приплыли.
На практике, пути длиннее 260 символов возникают достаточно редко. У меня, например, ни одного нет.
BFE>Из-за неизменной константы.
Так это системная константа, а не собственная в приложении. То есть, это одна из характеристик ОС, под которую делалось приложений. В линуксах ведь тоже все лезут напрямую в /bin, /usr/local/share, а не спрашивают систему о конкретных путях "именно здесь".
BFE>Перечисление — оно на то и перечисление, что само значений не хранит.
Оно не может не хранить значений, иначе его не реализовать. Вы хотели сказать — не отдает в явном виде?
BFE>А вот автоматическое сопоставление различных значений различных типов элементам перечислений было бы удобно и его реально не хватает.
Поддерживаю. Но лучше бы в качестве расширения, а не замены того, что есть.
BFE>Значит, что в нормальных перечислениях одному элементу перечисления может быть сопоставлено несколько разных значений.
Это уже не простое перечисление, а некий агрегат. Такое тоже полезно, но лишь в качестве дополнения к простому. В большом количестве задач фигурируют именно простые перечислимые значения, зачем искусственно усложнять?
BFE>А то, что в С++ в enum изначально была заявлена возможность явного задания значений — это от бедности и концептуально ошибочно.
Не от бедности, а от простоты и эффективности. Напомню, что уникальность C++ именно в том, чтобы иметь возможность работать сколь угодно близко к аппаратуре. Для абстракций наделали более других языков, но близости к аппаратуре больше нет нигде. И в C++ абстракции имеет смысл добавлять на абы как, а чтоб не поломать исходную идею "языка произвольного уровня".
BFE>Перечисление — это то, что можно перечислить.
Верно, но это не просто абстрактное множество, а упорядоченное.
BFE>Элементу перечисления можно сопоставить некоторые значения и сделать это можно различными способами. Другое дело, что делать сопоставление руками чревато ошибками.
Ваш явный способ через next ими еще более чреват.
BFE>Это как раз тот случай, когда изменение значения enum порождает отдалённые последствия.
Не более отдаленные, чем изменение значения любой числовой константы. Без них не обойтись, когда код не самодостаточен, а самодостаточного кода гораздо меньше, чем системно-зависимого.
BFE>Если вам не нужна шаблонная магия, то не используйте её.
Так я и не использую. А вот некоторые решения, которые более-менее компактно делаются только с ее помощью, мне как раз бывают нужны. Приходится городить традиционными способами.
ЕМ>>Какое метапрограммирование Вы сочли бы красивым?
BFE>Это сложный вопрос, я не готов на него ответить.
На мой взгляд, для красивого метапрограммирования необходимы средства как функциональной записи, давно продвигаемые в стандарт языка, так и процедурной, которой почему-то избегают любой ценой, будто она заразна.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Чтоб в шаблоне можно было как обращаться к его параметрам по индексам
Это уже грядет: https://en.cppreference.com/w/cpp/language/pack_indexing
ЕМ>Не от бедности, а от простоты и эффективности. Напомню, что уникальность C++ именно в том, чтобы иметь возможность работать сколь угодно близко к аппаратуре.
Наверное именно поэтому в C++ легально напрямую сравнивать (на больше/меньше) указатели только в случае, если они ссылаются на элементы одного и того же массива. И нужны костыли в виде std::launder и std::start_lifetime_as, потому что компилятор воображает себе невесть что. Размерности типов char, short, int, long в стандарте не зафиксированы, типы std::intN_t являются опциональными, а точная размерность типов int_fastN_t/int_leastN_t не определена. А пустой бесконечный цикл в main в текущих стандартах рассматривается как UB.
Сколь угодная близость к аппаратуре она же именно такая, да?
Здравствуйте, so5team, Вы писали:
S>В случае простых enum-ов оно не работает для типов, отличных от int. S>В случае enum class оно не работает для типов, отличных от целочисленных, да еще и требует указывать дополнительный скоуп. S>В общем, оно не работает. А я опять вляпался в известную субстанцию в попытках объяснить персонажам вроде вас очевидные вещи
Всё работает просто вы не так используете. В C++ принято всё через жопу делать
Здравствуйте, so5team, Вы писали:
S>Наверное именно поэтому в C++ легально напрямую сравнивать (на больше/меньше) указатели только в случае, если они ссылаются на элементы одного и того же массива. И нужны костыли в виде std::launder и std::start_lifetime_as, потому что компилятор воображает себе невесть что. Размерности типов char, short, int, long в стандарте не зафиксированы, типы std::intN_t являются опциональными, а точная размерность типов int_fastN_t/int_leastN_t не определена. А пустой бесконечный цикл в main в текущих стандартах рассматривается как UB.
S>Сколь угодная близость к аппаратуре она же именно такая, да?
Это называется over-engineering. Когда хочется что бы было очень научно. В результате из-за несогласованности в основании эта научность выливается в стандартизацию костылей.
Что грядет — хорошо. Но то, что грядет с опозданием на десятки лет — плохо. Ведь все это в разных формах было придумано и использовалось давным-давно, но многие ли знают историю до момента своего вхождения в профессию?
S>Наверное именно поэтому в C++ легально напрямую сравнивать (на больше/меньше) указатели только в случае, если они ссылаются на элементы одного и того же массива. И нужны костыли в виде std::launder и std::start_lifetime_as, потому что компилятор воображает себе невесть что.
В общем случае это вполне логично, поскольку разные массивы могут быть размещены в разных сегментах, и компилятор обязан это учитывать. Если на платформе плоская модель памяти, он может и не возбуждаться на эту ситуацию. Соответственно, реализации launder для этой платформы должны проверять, где находятся адреса.
S>Размерности типов char, short, int, long в стандарте не зафиксированы
Это не страшно, к размерам нетрудно привязаться через платформенно-зависимые заголовки.
S>пустой бесконечный цикл в main в текущих стандартах рассматривается как UB.
По-моему, пустой бесконечный цикл нигде не должен считаться нормой. Есть исключения?
S>Сколь угодная близость к аппаратуре она же именно такая, да?
Кое-в-чем могло быть и поближе, было бы неплохо. Главное, что это никак не мешает делать сколь угодно абстрактные программы, которым нужна предельная переносимость, а не предельная эффективность.
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>Элементы перечисления тоже не должны были бы видимы прямо из глобального пространства. ЕМ>Что-то я запутался. Когда я Вам приводил enum class в качестве примера разумного прогресса в языке, Вы ответили в том смысле, что "не очень-то и хотелось", поскольку enum можно было завернуть в namespace.
Нет, я ответил в том смысле, что убрать значения enum из глобального пространства — это не совсем та цель, которая ставилась при введении enum class. Основная цель — создание независимых типов.
BFE>>Ну было бы пересечение по имени ErrorCode ЕМ>И "увидели бы они, что это хорошо".
В каком смысле "хорошо"? Вот, допустим, у вас два разных enum и оба называются ErrorCode. Что делать?
BFE>>Добавление нового элемента в середину перечисления приводит к просмотру и правке всего кода, который прямо или косвенно связан с константами. Изменение значения элемента перечисления приводит просмотру и правке всего кода, который прямо или косвенно связан с перечислением. ЕМ>И Вас не смущает, что код, требующий такого пересмотра, фундаментально ущербен?
Вообще-то я об этом пишу с самого начала.
ЕМ>Если код определяет "просто перечисление", то он не имеет оснований закладываться ни на количество элементов, ни на их значения — только на то, что они будут уникальными в пределах перечисления, и возрастать монотонно.
Да.
ЕМ> Вы еще посетуйте, что код, закладывающийся на порядок следования данных-членов класса, их смещения и размеры, ломается при вставке новых членов в середину.
Код, который закладывается на порядок следования данных-членов класса встречается намного реже, чем enum как константы.
ЕМ>Если код таки закладывается на значения элементов и/или соотношения между ними, то нужно или принимать меры, которые я упоминал выше (например, добавлять элементы вида Group1_First, Group1_Last, Group2_First, Group2_Last и т.п.), или определять эти значения явно (против чего вы почему-то активно выступаете). На самый худющий конец — обернуть этот enum огромнейшим комментарием, обещающим ужасные кары тому, кто осмелится его менять неподобающим образом, и вдобавок наставить assert'ов, проверяющих соотношения.
А можно просто не использовать enum как константы.
ЕМ>>>Если вдруг нужен пакет разнотипных параметров, то или никак, или через вырвиглазные трюки. BFE>>Ерунду пишите. Нет тут ничего вырвиглазного:
ЕМ>А сможете этот пакет разобрать поштучно непосредственно в шаблоне, чтобы, в зависимости от типов, породить произвольный код, и чтоб это не выглядело похожим на традиционное "char* (*(*foo[5])(char*))[];", которым только детей пугать?
Что ещё за "произвольный" код? В зависимости от типа в примере и так вызывается разный код.
BFE>>Сомневаюсь, что такое вообще возможно без рантайм информации о типе. ЕМ>Зачем здесь рантайм? Я говорю исключительно о времени компиляции. Чтоб в шаблоне можно было как обращаться к его параметрам по индексам, так и записать конструкцию псевдоцикла, перебирающего параметры, узнающего у компилятора свойства фактических параметров, чтоб в итоге порождать код в зависимости от любых необходимых условий.
Возьмите кортеж и будет там обращение по индексам. Но зачем?
Что такое псевдоцикл?
Порождать код? Т.е. вы хотите автоматическую кодогенерацию? Метапрограммирование? Это интересная возможность и было бы не плохо её добавить в C++, пока что в планах у комитета вот такое: p2996r4
ЕМ>То есть, чтоб шаблон работал подобно обычной функции, работающей со своими фактическими параметрами через имена формальных, но вместо выполнения операторов порождал код для последующей компиляции, как это делает любой адекватный макропроцессор.
Хотелки — хотелками, а "Если вдруг нужен пакет разнотипных параметров, то или никак, или через вырвиглазные трюки", то и сейчас никаких вырвиглазных трюков.
BFE>>Убеждён, что если же вам нужна рантайм информации о типе, значит вы что-то не понимаете в программировании на C++. ЕМ>А если я что-то понимаю, но информация мне все равно нужна? Например, в сугубо отладочных целях?
Вангую: в ближайшие двадцать лет появятся отладчики для процесса компиляции.
ЕМ>Из Вашего утверждения также следует, что массивы в языке тоже являются вредным излишеством. Ну, или Вы меня неправильно поняли.
Очевидно, проблемы с взаимным пониманием.
BFE>>мне не сложно было бы их прописать так, как я уже это делал выше: BFE>>
BFE>>constexpr int b = next(a);
BFE>>constexpr int c = next(b);
BFE>>
ЕМ>Во-первых, даже для десятка-другого это будет чрезмерно громоздко (а следовательно, менее понятно и наглядно) по сравнению с enum. Во-вторых, большинство имен придется указывать в двух местах, а это влечет за собой известную проблему согласованности, но средств автоматизированного обеспечения согласованности у нас нет. Я не вижу в таком способе ни одного преимущества перед enum, но вижу серьезные недостатки.
Не обязательно писать так примитивно, можно и разного универсального накрутить.
Вот чуть более продвинутый пример: здесь
. На его основе можно написать сколь угодно сложную инициализацию констант.
ЕМ>В смысле, на конкретные численные значения? Для этого достаточно даже простого перечисления имен в enum, а если нам нужно знать о них что-то большее, то конкретные значения появляются только в одном месте, во всех остальных используются только имена. То есть, на конкретные значения никто не полагается — в точке определения их можно менять, и нигде ничего не поломается.
Я рад за вас и вашу веру в "на конкретные значения никто не полагается".
У меня вопрос: как часто вы правите чужие исходники?
ЕМ>Если Вы о том, чтобы завернуть все это в объект, то такое не прокатит в глобальном масштабе. Если ОС будет предоставлять интерфейс на продвинутом C++, разработчики других языков замучатся их сопрягать. Они и с традиционным сишным не всегда могут сопрячь.
Обёртку для C++ вполне можно написать.
ЕМ>Да, это недостаток. Но, увы, пока неустранимый.
Вполне устранимый, если не на прямую с API работать.
ЕМ>На практике, пути длиннее 260 символов возникают достаточно редко. У меня, например, ни одного нет.
А я часто на это нарываюсь. Вот пример здесь
.
BFE>>Из-за неизменной константы. ЕМ>Так это системная константа, а не собственная в приложении. То есть, это одна из характеристик ОС, под которую делалось приложений. В линуксах ведь тоже все лезут напрямую в /bin, /usr/local/share, а не спрашивают систему о конкретных путях "именно здесь".
Не, система-то как раз поддерживает длинные пути, а вот приложение — нет.
BFE>>Перечисление — оно на то и перечисление, что само значений не хранит. ЕМ>Оно не может не хранить значений, иначе его не реализовать. Вы хотели сказать — не отдает в явном виде?
Может не хранить в том смысле, что они могут различаться от закуска к запуску, например.
ЕМ>Это уже не простое перечисление, а некий агрегат.
Не обязательно делать его одним объектом.
ЕМ>Такое тоже полезно, но лишь в качестве дополнения к простому. В большом количестве задач фигурируют именно простые перечислимые значения, зачем искусственно усложнять?
Почему вы пишите значения, если речь о именах?
BFE>>А то, что в С++ в enum изначально была заявлена возможность явного задания значений — это от бедности и концептуально ошибочно. ЕМ>Не от бедности, а от простоты и эффективности. Напомню, что уникальность C++ именно в том, чтобы иметь возможность работать сколь угодно близко к аппаратуре. Для абстракций наделали более других языков, но близости к аппаратуре больше нет нигде. И в C++ абстракции имеет смысл добавлять на абы как, а чтоб не поломать исходную идею "языка произвольного уровня".
Перечисления к аппаратуре имеют весьма опосредствованное отношение.
BFE>>Перечисление — это то, что можно перечислить. ЕМ>Верно, но это не просто абстрактное множество, а упорядоченное.
Не обязательно. Зачем упорядоченность?
BFE>>Элементу перечисления можно сопоставить некоторые значения и сделать это можно различными способами. Другое дело, что делать сопоставление руками чревато ошибками. ЕМ>Ваш явный способ через next ими еще более чреват.
Не путайте: next — это для констант.
BFE>>Это как раз тот случай, когда изменение значения enum порождает отдалённые последствия. ЕМ>Не более отдаленные, чем изменение значения любой числовой константы.
Меняется не просто значение, меняется тип, в который может перечисление конвертироваться.
ЕМ>Без них не обойтись, когда код не самодостаточен, а самодостаточного кода гораздо меньше, чем системно-зависимого.
Самодостаточного кода намного больше, чем системно-зависимого.
ЕМ>На мой взгляд, для красивого метапрограммирования необходимы средства как функциональной записи, давно продвигаемые в стандарт языка, так и процедурной, которой почему-то избегают любой ценой, будто она заразна.
Не избегают, а реализовать не могут из-за сложности.
А вы много лет продвигали правильный вариант, но ваше мнение игнорировали? Или много лет спонсировали комитет по стандартизации, а он упорно не принимал то, что вы хотели?
ЕМ>Ведь все это в разных формах было придумано и использовалось давным-давно
Примеры можно? Может вы про PL/1?
ЕМ>но многие ли знают историю до момента своего вхождения в профессию?
Вы и сейчас дофига не знаете. Что не мешает вам вещать пургу с умными видом и уныло сливаться как только речь заходит о конкретике.
S>>Наверное именно поэтому в C++ легально напрямую сравнивать (на больше/меньше) указатели только в случае, если они ссылаются на элементы одного и того же массива. И нужны костыли в виде std::launder и std::start_lifetime_as, потому что компилятор воображает себе невесть что.
ЕМ>В общем случае это вполне логично, поскольку разные массивы могут быть размещены в разных сегментах, и компилятор обязан это учитывать. Если на платформе плоская модель памяти, он может и не возбуждаться на эту ситуацию.
Указатель это такая абстракция в C++, которая скрывает от программиста что из себя представляет адрес на конкретной платформе. Это, блин, ну просто максимально близкий к железу уровень. Ага.
ЕМ>Соответственно, реализации launder для этой платформы должны проверять, где находятся адреса.
Может стоило бы подучить матчасть, тем более, что она появилась уже после вашего вхождения в профессию. Просто чтобы глупости не говорить. Хотя бы про launder.
ЕМ>По-моему, пустой бесконечный цикл нигде не должен считаться нормой. Есть исключения?
Здравствуйте, B0FEE664, Вы писали:
BFE>убрать значения enum из глобального пространства — это не совсем та цель, которая ставилась при введении enum class. Основная цель — создание независимых типов.
Почему "создание"? enum в C++ изначально представляет собой тип.
BFE>допустим, у вас два разных enum и оба называются ErrorCode. Что делать?
То же самое, если два разных класса, глобальных объекта, функции с одинаковыми именами.
ЕМ>>Вас не смущает, что код, требующий такого пересмотра, фундаментально ущербен?
BFE>Вообще-то я об этом пишу с самого начала.
Мне показалось, что Вы считаете ущербной как раз реализацию enum, а код, который от него ломается — невинной жертвой.
Я же не вижу проблем написать с помощью enum код, который как вообще не зависит от количества/порядка элементов, так и зависит от него с минимальным риском поломки. По-моему, здесь достаточно широкий спектр возможностей.
BFE>Код, который закладывается на порядок следования данных-членов класса встречается намного реже, чем enum как константы.
Это просто потому, что из порядка членов меньше возможностей извлечь практическую пользу.
BFE>А можно просто не использовать enum как константы.
Так можно и int не использовать, а на каждый числовой тип создавать свой класс с набором операций. Но где-то придется остановиться.
BFE>Что ещё за "произвольный" код? В зависимости от типа в примере и так вызывается разный код.
У Вас есть возможность подставить только вызов функции, но не любой код, синтаксически допустимый в этом месте.
BFE>Возьмите кортеж и будет там обращение по индексам. Но зачем?
Незачем, ибо кортежем можно манипулировать только во время выполнения, а я говорю про время компиляции.
BFE>Что такое псевдоцикл?
Цикл, который крутится во время компиляции, перебирая фактические параметры шаблона, элементы кортежа, или даже просто порождая копии кода (одинаковые или зависящие от итерации).
BFE>Порождать код? Т.е. вы хотите автоматическую кодогенерацию? Метапрограммирование?
Хочу.
BFE>Это интересная возможность и было бы не плохо её добавить в C++, пока что в планах у комитета вот такое
Как всегда, корявенько. Все пытаются сделать покороче, сэкономить несколько символов, хотя полные конструкции уже давно стали весьма развесистыми. Лучше б обозначать набор свойств типа по аналогии со структурой: T.type_id, T.type_name, T.is_arithmetic, T.num_of_members, T.members [2].is_function, T.members [2].args [3].type_id, и т.п.
BFE>"Если вдруг нужен пакет разнотипных параметров, то или никак, или через вырвиглазные трюки", то и сейчас никаких вырвиглазных трюков.
Это если развернуть пакет в подстановку вызовов функций, которые определены где-то отдельно. А разобрать пакет по параметрам, подставив каждый из них более другим образом, сейчас можно только через магию с рекурсией, и выглядит это ну очень вырвиглазно. А главное — чужеродно и непоследовательно. Каждое новое решение приходится втискивать в старый синтаксис, который и без того же давно перегружен.
BFE>Вангую: в ближайшие двадцать лет появятся отладчики для процесса компиляции.
По уму, должны были появиться лет двадцать пять назад, когда активно пошли в ход вложенные и рекурсивные шаблоны. На худой конец — возможность вывода отладочной информации на каждой стадии разбора/обработки/подстановки.
BFE>Не обязательно писать так примитивно, можно и разного универсального накрутить. BFE>Вот чуть более продвинутый пример: здесь
. На его основе можно написать сколь угодно сложную инициализацию констант.
А можно и базу данных прикрутить...
BFE>Я рад за вас и вашу веру в "на конкретные значения никто не полагается".
Каким именно образом полагаются там, где Вы видели?
BFE>как часто вы правите чужие исходники?
Редко. Такое, чтоб использовало enum прям совсем уж коряво, попадалось редко.
BFE>Обёртку для C++ вполне можно написать.
Так и пишут. У меня самого классы для работы с кодами ошибок ОС.
ЕМ>>Да, это недостаток. Но, увы, пока неустранимый. BFE>Вполне устранимый, если не на прямую с API работать.
ЕМ>>На практике, пути длиннее 260 символов возникают достаточно редко. У меня, например, ни одного нет. BFE>А я часто на это нарываюсь.
Какая необходимость заставляет использовать софт из-под Win9x с непременно в дереве каталогов, у которого одновременно и много уровней, и длинные имена?
Если у GCC это ограничение сохранялось аж до 2021-го — значит, до Вас на него нарывались максимум единицы из десятков-сотен тысяч. Это к вопросу о хотелках и степени их важности.
BFE>Может не хранить в том смысле, что они могут различаться от закуска к запуску, например.
Это уже какая-то очень динамическая реализация, на основе тех же списков/кортежей. Делать такое для десятков-сотен одних и тех же элементов — чрезмерно. enum как раз и хорош тем, что позволяет создавать разнообразные и одновременно эффективные наборы.
ЕМ>>Это уже не простое перечисление, а некий агрегат. BFE>Не обязательно делать его одним объектом.
Я ж говорю — надо БД. И непременно в облаке.
BFE>Почему вы пишите значения, если речь о именах?
Потому, что к подобным простым задачам вроде обсуждаемой идеально подходят именно числовые именованные значения, а не какие-то абстрактные.
BFE>Перечисления к аппаратуре имеют весьма опосредствованное отношение.
Отлично подходит для кодирования состояний устройства, внутренних функций, режимов работы, состояний драйвера/обработчика и подобного.
BFE>Зачем упорядоченность?
Тогда это не перечисление, а просто множество. Более общая сущность, не обладающая свойствами перечисления, которые часто бывают полезны.
Больше всего мне нравится перечислимый тип (cardinal) в Pascal/Modula — сами по себе это просто идентификаторы, которые можно использовать только в рамках своего типа, но для них определены порядковый номер (ord) и операции succ/pred, но нет возможности узнать количество элементов.
BFE>Меняется не просто значение, меняется тип, в который может перечисление конвертироваться.
Такие вещи должен отлавливать компилятор. Я всегда выступал за то, чтобы -W4 -Wall подразумевалось по умолчанию.
BFE>Самодостаточного кода намного больше, чем системно-зависимого.
Если кажется, что код не зависит от системы — значит, он зависит от библиотек, которые сопрягают его с системой. Стерильного кода, который вводит с абстрактной клавиатуры и выводит на абстрактный экран или ПУ, в общей массе немного.
ЕМ>>На мой взгляд, для красивого метапрограммирования необходимы средства как функциональной записи, давно продвигаемые в стандарт языка, так и процедурной, которой почему-то избегают любой ценой, будто она заразна.
BFE>Не избегают, а реализовать не могут из-за сложности.
Разумеется — на фоне того хаоса, который они устроили в языке, увязать все это будет непросто.
Здравствуйте, Евгений Музыченко, Вы писали:
BFE>>Не обязательно писать так примитивно, можно и разного универсального накрутить. BFE>>Вот чуть более продвинутый пример: здесь
Здравствуйте, so5team, Вы писали:
S>А вы много лет продвигали правильный вариант, но ваше мнение игнорировали? Или много лет спонсировали комитет по стандартизации, а он упорно не принимал то, что вы хотели?
Я, по наивности своей, долгое время думал, что там сплошь чертовски умные дядьки, не мне чета, и лучше знают, как развивать язык, а я просто хочу странного. Но постепенно, глядя на его развитие, сильно в этом усомнился. Как, собственно, и в политиках, экономистах, медиках и прочих.
Да что там язык — идея софта для заметок-напоминалок у меня тоже лет двадцать назад сложилась, но все было недосуг, плюс уверенность, что примерно то же самое вот-вот кто-то реализует, ибо все на поверхности. А нет, никто не сподобился. Может, сам как-нибудь возьмусь.
ЕМ>>все это в разных формах было придумано и использовалось давным-давно
S>Примеры можно? Может вы про PL/1?
Лень мне искать конкретные примеры — за много лет попадалось с десяток реализаций минимум. И в PL/1, и в ассемблере System/360, и в содранном с него макроассемблере БЭМШ для БЭСМ-6, и даже (в зачаточном виде) в ассемблерах для PC.
S>сливаться как только речь заходит о конкретике.
Так Вы ж все время требуете примеров кода, а мне лень их искать или специально сочинять, предпочитаю описывать словами. Я не отношусь к числу людей, мозги которых свободно оперируют конструкциями "возьмем S такое, что <трехэтажная формула>".
S>Указатель это такая абстракция в C++, которая скрывает от программиста что из себя представляет адрес на конкретной платформе.
Она это скрывает от программиста, который не хочет этого знать, и может себе позволить такое незнание. Для тех, кто хочет и может, в реализациях обычно достаточно способов привязки. Их все нет смысла тащить в стандарт, чтоб не загромождать его еще больше — разве что некоторые.
ЕМ>>Соответственно, реализации launder для этой платформы должны проверять, где находятся адреса.
S>Может стоило бы подучить матчасть, тем более, что она появилась уже после вашего вхождения в профессию. Просто чтобы глупости не говорить. Хотя бы про launder.
Он мне никогда не был нужен, поэтому я никогда о нем и не читал. Глянул мельком — вот и показалось на фоне Вашего контекста, что он действительно приводит указатель к "нейтральному" виду, допускающему сравнение с чем угодно.
ЕМ>>По-моему, пустой бесконечный цикл нигде не должен считаться нормой. Есть исключения?
S>https://rsdn.org/forum/cpp/8600448.1
Негодный пример — такой цикл будет жрать энергию и греть МК, поэтому в качестве сколько-нибудь рабочего категорически не годится — нужно вставлять хотя бы вызов типа sleep/yield для конкретной платформы. А если уж кому-то приспичило крутить именно непрерывный, который греет — может вставить туда какие-нибудь "тяжелые" операции, чтоб греть сильнее.
Такой вот непроизвольный защитный барьер получился.
Здравствуйте, Евгений Музыченко, Вы писали:
S>>А вы много лет продвигали правильный вариант, но ваше мнение игнорировали? Или много лет спонсировали комитет по стандартизации, а он упорно не принимал то, что вы хотели?
ЕМ>Я, по наивности своей, долгое время думал, что там сплошь чертовски умные дядьки, не мне чета, и лучше знают, как развивать язык, а я просто хочу странного. Но постепенно, глядя на его развитие, сильно в этом усомнился. Как, собственно, и в политиках, экономистах, медиках и прочих.
А вы попробуйте принять участие в развитии языка. Ну или пообщайтесь с теми, кто этим занимается. Пока же вы лишь подтверждаете житейскую мудрость "каждый мнит себя стратегом видя бой со стороны".
ЕМ>Да что там язык — идея софта для заметок-напоминалок у меня тоже лет двадцать назад сложилась, но все было недосуг, плюс уверенность, что примерно то же самое вот-вот кто-то реализует, ибо все на поверхности. А нет, никто не сподобился. Может, сам как-нибудь возьмусь.
Возьмитесь, сделайте, явите миру. Уверяю вас, найдется множество таких же Музыченко, как вы, которые найдут в сделанном вами кучу фатальных недостатков.
ЕМ>>>все это в разных формах было придумано и использовалось давным-давно
S>>Примеры можно? Может вы про PL/1?
ЕМ>Лень мне искать конкретные примеры — за много лет попадалось с десяток реализаций минимум.
Музыченко as is.
ЕМ>И в PL/1
Это в том, который еще во времена своей востребованности стал эталоном того, как делать не нужно? Так себе ориентир.
ЕМ>Так Вы ж все время требуете примеров кода, а мне лень их искать или специально сочинять, предпочитаю описывать словами.
Во-первых, это говорит о том, что вы не разбираетесь в предмете разговора.
Во-вторых, это не оставляет места для предметного общения и шансов на хоть какой-то конструктивный выхлоп.
ЕМ>Я не отношусь к числу людей, мозги которых свободно оперируют конструкциями "возьмем S такое, что <трехэтажная формула>".
Здесь не нужно трехэтажных формул. А вот фрагменты кода, раз уж речь про удобство языка программирования, должны быть. Иначе нет предмета самого разговора.
S>>Указатель это такая абстракция в C++, которая скрывает от программиста что из себя представляет адрес на конкретной платформе.
ЕМ>Она это скрывает от программиста, который не хочет этого знать, и может себе позволить такое незнание. Для тех, кто хочет и может, в реализациях обычно достаточно способов привязки.
И тут мы опять без примеров?
Это во-первых.
А во-вторых, я вам не зря про std::launder и std::start_lifetime_as. Это все о том, что в современном C++ мало присвоить указателю какое-то собственное значение. Еще и нужно компилятору объяснить, что это не абы что. Иначе продвинутый компилятор пошлет все ваши потуги вдоль. Что очень странно для языка, в котором вы видите близость к железу.
ЕМ>>>Соответственно, реализации launder для этой платформы должны проверять, где находятся адреса.
S>>Может стоило бы подучить матчасть, тем более, что она появилась уже после вашего вхождения в профессию. Просто чтобы глупости не говорить. Хотя бы про launder.
ЕМ>Он мне никогда не был нужен, поэтому я никогда о нем и не читал. Глянул мельком — вот и показалось на фоне Вашего контекста, что он действительно приводит указатель к "нейтральному" виду, допускающему сравнение с чем угодно.
Еще одно подтверждение тому, что вы звиздите о том, о чем не имеете понятия.
ЕМ>>>По-моему, пустой бесконечный цикл нигде не должен считаться нормой. Есть исключения?
S>>https://rsdn.org/forum/cpp/8600448.1
p2996r4 ЕМ>Как всегда, корявенько. Все пытаются сделать покороче, сэкономить несколько символов, хотя полные конструкции уже давно стали весьма развесистыми. Лучше б обозначать набор свойств типа по аналогии со структурой: T.type_id, T.type_name, T.is_arithmetic, T.num_of_members, T.members [2].is_function, T.members [2].args [3].type_id, и т.п.
Такой синтаксис не подойдёт для случая, когда type_id надо узнать у переменной. Везде придётся писать decltype: struct A { int i; } a;
decltype(a.i).type_id
Ну, попустим. А дальше что? Какая конструкция переведёт T.type_name обратно в тип?