Здравствуйте, Pzz, Вы писали:
Pzz>Если у тебя в программе переменная/класс/функция назывались import или export
export, насколько я помню, был ключевым словом еще со времен C++98.
Кроме того, ряд ключевых слов в современном C++ (Google подсказывает: override, final, module, import, requires) являются контекстно-зависимыми. Т.е. они играют роль ключевого слова только будучи использованными в определенном контексте. Т.е. если в коде были такие имена переменных/функций, то это проблемой стать не должно.
Здравствуйте, so5team, Вы писали:
Pzz>>Если у тебя в программе переменная/класс/функция назывались import или export
S>export, насколько я помню, был ключевым словом еще со времен C++98.
Ты с extern не путаешь?
S>Кроме того, ряд ключевых слов в современном C++ (Google подсказывает: override, final, module, import, requires) являются контекстно-зависимыми. Т.е. они играют роль ключевого слова только будучи использованными в определенном контексте. Т.е. если в коде были такие имена переменных/функций, то это проблемой стать не должно.
Да, я заметил. Но вот alignof, например — полноценное ключевое слово.
Здравствуйте, Pzz, Вы писали:
Pzz>>>Если у тебя в программе переменная/класс/функция назывались import или export
S>>export, насколько я помню, был ключевым словом еще со времен C++98.
Pzz>Ты с extern не путаешь?
А вот вас, не знающего C++ от слова совсем, но упорно о нем рассуждающего, следовало бы гнать отсюдова ссаными тряпками. От Шмыги кое-как избавились, но вы, блин, хуже таракана.
Pzz>Да, я заметил. Но вот alignof, например — полноценное ключевое слово.
Его, вместе с alignas, ввели в C++11, где и так много чего поломали. А после того, как некий условный проект пережил переход с C++98 на С++11, дальше все уже гораздо проще и менее болезненно. Тем более, что во вменяемых компиляторах есть ключик -std, который позволяет зафиксировать версию C++ для проекта и не боятся нововведений из свежих стандартов.
Здравствуйте, so5team, Вы писали:
S>А вот вас, не знающего C++ от слова совсем, но упорно о нем рассуждающего, следовало бы гнать отсюдова ссаными тряпками. От Шмыги кое-как избавились, но вы, блин, хуже таракана.
Голубчик, вы неисправимый хам.
Вы столь же невежливы, невоспитанны и категоричны, как Ульрих Дреппер и Линус Торвальдс. Но что-то я и близко не вижу Ваших достижений, сравнимых с ними.
Здравствуйте, Pzz, Вы писали:
Pzz>Вы столь же невежливы, невоспитанны и категоричны, как Ульрих Дреппер и Линус Торвальдс. Но что-то я и близко не вижу Ваших достижений, сравнимых с ними.
А вы считаете, что хамство может быть оправдано достижениями?
Здравствуйте, so5team, Вы писали:
Pzz>>Вы столь же невежливы, невоспитанны и категоричны, как Ульрих Дреппер и Линус Торвальдс. Но что-то я и близко не вижу Ваших достижений, сравнимых с ними.
S>А вы считаете, что хамство может быть оправдано достижениями?
Я считаю, что оно ничем не может оправдано.
Но при наличии достижений хоть понятно, за что мы этих людей терпим.
Здравствуйте, Pzz, Вы писали:
Pzz>>>Вы столь же невежливы, невоспитанны и категоричны, как Ульрих Дреппер и Линус Торвальдс. Но что-то я и близко не вижу Ваших достижений, сравнимых с ними.
S>>А вы считаете, что хамство может быть оправдано достижениями?
Pzz>Я считаю, что оно ничем не может оправдано.
Pzz>Но при наличии достижений хоть понятно, за что мы этих людей терпим.
Ну вот и я не понимаю, зачем вас здесь терпеть: знаний C++ нет, достижений нет, только одни повторяющиеся снова и снова лозунги о том, насколько C++ дерьмовый язык.
Здравствуйте, so5team, Вы писали:
Pzz>>Но при наличии достижений хоть понятно, за что мы этих людей терпим.
S>Ну вот и я не понимаю, зачем вас здесь терпеть: знаний C++ нет, достижений нет, только одни повторяющиеся снова и снова лозунги о том, насколько C++ дерьмовый язык.
Не Вам решать, терпеть меня здесь или не терпеть.
Что до моих достижений, Гугль в помощь. Сам я себя нахваливать не буду.
Здравствуйте, Pzz, Вы писали:
Pzz>Не Вам решать, терпеть меня здесь или не терпеть.
Не мне решать банить ли вас здесь или нет.
Но если мне видится, что никакого конструктива или даже элементарной объективности вы в обсуждения языка C++ не привносите (причем от слова совсем), то ничто не препятствует заявить вам, что вашему унылому мнению здесь не рады (хотя бы даже в лице только меня).
Pzz>Сам я себя нахваливать не буду.
Типа есть чем? Может покажите какую-то свою кодовую базу на C++, которая позволит понять, что вы в C++ разбираетесь?
SP>это шутка? Офигеть как просто. На каждый тип заводить структуру на 100 строк. enum class здесь нужен не как перечисление, а просто обёртка для типа, чтобы запретить неявные касты и дать из коробки операции сравнения. Это способ создать strong type быстро и по месту. То что вы привели — совсем из другой оперы.
структуру на 100 строк? Ну, если у вас enum на 100 значений, то вам понадобится 105 строк:
PS: всё это можно расширить и углубить вплоть до построения автоматического списка значений при инициализации констант и даже далее. После того как разрешили inline static константы произвольного типа декларировать и инициализировать прямо внутри класса с гарантией на порядок инициализации, встроенные enum'ы стали не нужны. Просто инерция мышления и полученное образование не позволяет взглянуть на задачу вне колеи столбовой дороги.
Здравствуйте, B0FEE664, Вы писали:
BFE>Ну или я не понял, чего вы там хотите...
не поняли. Посмотрите название темы. Я про сильные типы, а вы мне про то, как реализовать перечисление на строках.
Есть уже такой паттерн в С++ — использовать для создания сильных типов enum class. Н-р в стандартной библиотеке std::byte его уже использует.
enum class byte: unsigned char {};
Заметьте внутри никаких специальных значений. Т. е. enum используется совсем не по прямому своему назначению.
Но этот подход имеет один огромный недостаток. Он применим только для целых. Даже для float нельзя (на самом деле можно, но требует уже извратов).
И вот я предлагаю вместо ввода неуклюжих аттрибутов (как в стартовом сообщении) просто расширить применение enum class на float и структуры. Согласитесь, намного проще сделать так
enum class UserId: size_t {};
enum class PassportId: std::string {};
PassportId getPassportById(UserId id);
Вместо одной строчки писать целую структуру для определения PassportId я категорически не согласен. Есть правда подход с BOOST_STRONG_TYPEDEF, который фактически прячет нашу структуру под макрос. Но тоже имеет массу неудобств. И в нём как раз определить специальные значения не получится (н-р Invalid для PassportId).
Здравствуйте, sergii.p, Вы писали:
SP>Есть уже такой паттерн в С++ — использовать для создания сильных типов enum class. Н-р в стандартной библиотеке std::byte его уже использует. SP>
SP>enum class byte: unsigned char {};
SP>
SP>Заметьте внутри никаких специальных значений. Т. е. enum используется совсем не по прямому своему назначению.
А...
Вы про это мертворождённое извращение.
Его никто не использовал, не использует и использовать не будет.
SP>Но этот подход имеет один огромный недостаток. Он применим только для целых. Даже для float нельзя (на самом деле можно, но требует уже извратов). SP>И вот я предлагаю вместо ввода неуклюжих аттрибутов (как в стартовом сообщении) просто расширить применение enum class на float и структуры. Согласитесь, намного проще сделать так
SP>
SP>enum class UserId: size_t {};
SP>enum class PassportId: std::string {};
SP>PassportId getPassportById(UserId id);
SP>
Всё это баловство, а не серьёзный подход.
И атрибуты эти — тоже не серьёзно.
Я их не буду использовать в предлагаемом виде и вам не советую.
Я несколько раз порывался написать как частные, так и специальные строгие типы.
Оказалось, что это либо очень сложно (для чисел), либо не нужно (для id). Не нужно в том плане, что я не поймал ни одной ошибки вида: "сравнил id паспорта с id билета".
Впрочем, если для id вам нужен строгий тип, то, опять же, он пишется очень просто:
template<class TValue, class TTag>
class Id
{
TValue m_value{};
// операции доступа и сравнения
};
struct PassportIdTag{};
using PassportId = Id<std::string, PassportIdTag>;
всё.
Вот только на практике возникает большое желание как можно точнее определять диапазоны или наборы допустимых значений. Вот ваш PassportId может быть длиной в 1024 символа? Нет? А кто и когда это проверяет? Для проверки код придётся написать так или иначе. В результате получается, что проще написать полноценный класс, чем возится с этими "строгими" типами.
Единственное применение, которое может быть полезно — это ускорение чтения кода. Что-нибудь вроде MyFunction(std::chrono::seconds(1));. Но и то, это уже вызовет вопросы, так как всякая константа должна иметь выразительное имя, а не захардкодена вот так. К тому же я не представляю, как подобный код может выглядеть для PassportId. Если MyFunction(PassportId("invalid")), то вот этот PassportId("invalid") точно должен быть вынесен в отдельную именованную константу.
Здравствуйте, B0FEE664, Вы писали:
BFE>Вы про это мертворождённое извращение. BFE>Его никто не использовал, не использует и использовать не будет.
А что именно называется "мертворожденным извращением": enum class или std::byte?
BFE>Вот только на практике возникает большое желание как можно точнее определять диапазоны или наборы допустимых значений.
Не нужно говорить за всех.
Мне давеча довелось написать класс, который в некоторых методах принимает на вход std::size_t (индекс значения), а внутри хотелось оперировать производными от std::size_t вариантами: valid_index, cluster_index, chunk_index, cluster_size, chunk_size. Причем cluster_size нужно было умножать на chunk_size, а valid_index нужно было уметь делить на std::size_t и брать остаток от деления на chunk_size.
Чтобы не париться и не выписывать "правильные" классы, было сделано очень просто, что-то вроде:
PS. Примитивные варианты со strong_typedef на базе шаблонов я тоже применял. За неимением лучшего -- OK, но каждый шаблон, пусть даже маленький, в итоге сказывается на скорости компиляции
Здравствуйте, B0FEE664, Вы писали:
BFE>Оказалось, что это либо очень сложно (для чисел), либо не нужно (для id). Не нужно в том плане, что я не поймал ни одной ошибки вида: "сравнил id паспорта с id билета".
ну а я поймал. Причём сразу и много.
К тому же это самоспецификация кода. Что лучше?
std::unordered_map<int/*task id*/, int/*server id*/> map;
int getServerIdByTaskId(int id);
В общем, я согласен, что это минорный рефакторинг, но очень полезный. И тут в полный рост становится вопрос: какой ценой. Если вы будете вводить структуру на 100 строчек, то точно — нет. А именно столько надо написать. Вы вот допишите ваш пример до конца и мы взглянем. Вы как-то обошли стороной конструкторы, операторы доступа, явные приведения, функцию хеширования, операции сравнения. А вот если такой тип вводится одной строчкой — нет проблем!
Здравствуйте, so5team, Вы писали:
S>Мне давеча довелось написать класс, который в некоторых методах принимает на вход std::size_t (индекс значения), а внутри хотелось оперировать производными от std::size_t вариантами: valid_index, cluster_index, chunk_index, cluster_size, chunk_size. Причем cluster_size нужно было умножать на chunk_size, а valid_index нужно было уметь делить на std::size_t и брать остаток от деления на chunk_size.
я такое реализовывал на основе enum class. Но только разрешал сложение и вычитание. Потому что размерность при этих операциях не меняется. Например так
template <typename E>
concept ArithmeticEnabled = requires(E e) {
enableArithmeticOperations(e);
};
template <ArithmeticEnabled E>
constexpr E operator+(E lhs, E rhs) {
using UT = std::underlying_type_t<E>;
return static_cast<E>(static_cast<UT>(lhs) + static_cast<UT>(rhs));
}
//использованиеenum class meters{};
constexpr void enableArithmeticOperations(meters);
А вот при умножении обычно меняется размерность и следовательно получается новый сильный тип (как при умножении метров получается m^2). И тут уже проще ручками определить.
enum class cluster_size: std::size_t {};
enum class chunk_size: std::size_t {};
enum class total_size: std::size_t {};
total_size operator*(cluster_size, chunk_size);
Здравствуйте, Pzz, Вы писали:
Pzz>И впрямь. Ну что за уродский язык? Прям как Питон...
Я бы сказал, уродство не во введении новых слов, а в том, что они отменяют соответствующие идентификаторы, при этом ломая совершенно постороннее. У вас новая версия, а автор используемой библиотеки говорит, что он не будет переименовывать функцию из export только из-за того, что какие-то стандартизаторы какого-то C++ чего-то постановили.
И идёте искать платформенно-зависимые средства для борьбы с этим.
Вон в Rust есть редакции языка, прибивку к которым надо явно указывать в начале исходного файла, и есть синтаксис `r#`, например, можно сослаться на функцию `if` через `r#if`. В C# есть префикс `@` перед именами с тем же результатом. А тут даже сформулировать проблему не хотят.
Когда у меня было время и настроение помечтать о своём языке, там были префиксы `$` для идентификатора и `@` для ключевого слова, причём ряд слов воспринимались только с этим @, объединяясь с интринсиками. Что-то похожее сейчас в Zig.
Но на практике случай, когда надо что-то переименовать ради новой версии языка, это таки редкость. Я помню, лет 5 назад где-то у меня был API с полем `class`, и переход C→C++ потребовал переименования. Может, потому и не заморачиваются.
Не в наезд на C++, но вариант "type Temperature = new Integer -100..100;" был в Ada с официального рождения, слово new давало нужный эффект.
Но за всем этим с…пором о том, применять protected или нет, мне больше интересен практический контроль конверсий. Вот у меня две такие температуры, одна в цельсиях, другая в кельвинах. Прямое присвоение в явном виде даст ерунду, а как сделать, чтобы оно было, если вообще используют, откровенно многословным и явным? Это предложение поможет такому?
Здравствуйте, netch80, Вы писали:
Pzz>>И впрямь. Ну что за уродский язык? Прям как Питон...
N>Я бы сказал, уродство не во введении новых слов, а в том, что они отменяют соответствующие идентификаторы, при этом ломая совершенно постороннее. У вас новая версия, а автор используемой библиотеки говорит, что он не будет переименовывать функцию из export только из-за того, что какие-то стандартизаторы какого-то C++ чего-то постановили. N>И идёте искать платформенно-зависимые средства для борьбы с этим.
Ну вот я и говорю, как Питон. Там тоже совершенно не заморачиваются обратной совместимостью языка.
Я тут очень избалован Go, где любая программа, валидная (согласно спецификации) сейчас, с очень высокой степенью вероятности останется валидной и потом. Обратная сторона вопроса — авторы Go могут думать 5 лет прежде, чем добавят какую-нибудь фишечку в язык. А могут и передумать, если в результате многолетних раздумий они вдруг придумают, что если в программе вот так вот встать, да вот так потянуться, да вот так почесаться, то с новой фишечкой она и не соберётся, хотя никаких спецификаций не нарушает.
N>Когда у меня было время и настроение помечтать о своём языке, там были префиксы `$` для идентификатора и `@` для ключевого слова, причём ряд слов воспринимались только с этим @, объединяясь с интринсиками. Что-то похожее сейчас в Zig.
Напоминает Perl
N>Но на практике случай, когда надо что-то переименовать ради новой версии языка, это таки редкость. Я помню, лет 5 назад где-то у меня был API с полем `class`, и переход C→C++ потребовал переименования. Может, потому и не заморачиваются.
Да, но в C++ очень много ключевых слов. Хочется ведь свои идентификаторы приятными словами называть, короткими, выразительными и общеизвестными. А комитету тоже их хочется. Поэтому вероятность столкновения велика.
Здравствуйте, Pzz, Вы писали:
Pzz>Ну вот я и говорю, как Питон. Там тоже совершенно не заморачиваются обратной совместимостью языка.
Заморачиваются. Но не настолько, конечно. Нормальным считается, когда один код одинаково работает сейчас в пределах 3-4 версий языка (например, от 3.8 до 3.11), но и на более далёкие интервалы стараются минимизировать изменения. Кошмарик перехода 2→3 стараются не повторять.
Конечно, это не настолько удобно. Я вот сейчас из-за одного стека, который работает только с 3.9 и 3.10, должен тянуть старое окружение… я ещё не разбирался, почему они не хотят 3.11, но стоит явное ограничение у пакета. Чего-то напугались. Надо таки выделить настроение и глянуть…
Pzz>Я тут очень избалован Go, где любая программа, валидная (согласно спецификации) сейчас, с очень высокой степенью вероятности останется валидной и потом. Обратная сторона вопроса — авторы Go могут думать 5 лет прежде, чем добавят какую-нибудь фишечку в язык. А могут и передумать, если в результате многолетних раздумий они вдруг придумают, что если в программе вот так вот встать, да вот так потянуться, да вот так почесаться, то с новой фишечкой она и не соберётся, хотя никаких спецификаций не нарушает.
Ну мне таки подход Rust нравится. Хотите сидеть, условно, на фичах версии 1.18? Пожалуйста, только ничего нового не получите. А перед выкаткой нового оно несколько лет проходит в экспериментальном статусе, его надо явно разрешать соответствующими словами в исходнике. Ну и для 90+% устарелостей есть чёткая инструкция, как их заменять.
N>>Когда у меня было время и настроение помечтать о своём языке, там были префиксы `$` для идентификатора и `@` для ключевого слова, причём ряд слов воспринимались только с этим @, объединяясь с интринсиками. Что-то похожее сейчас в Zig. Pzz>Напоминает Perl
В перле эти префиксы были обязательны, у меня — нет.
Pzz>Да, но в C++ очень много ключевых слов. Хочется ведь свои идентификаторы приятными словами называть, короткими, выразительными и общеизвестными. А комитету тоже их хочется. Поэтому вероятность столкновения велика.
Ну вот я и удивляюсь, что не придумали хотя бы стандартизованный атрибут в виде
Здравствуйте, netch80, Вы писали:
N>Вот у меня две такие температуры, одна в цельсиях, другая в кельвинах. Прямое присвоение в явном виде даст ерунду, а как сделать, чтобы оно было, если вообще используют, откровенно многословным и явным? Это предложение поможет такому?