В свои некоторые плюсовые либы и проекты хочу присунуть возможность отключать некоторые фичи при помощи препроцессора.
Напрашивается имя DISABLE_XXX, где 'XXX' — отключаемая фича или даже библиотека какая-то, со всеми её фичами.
С другой стороны в либе 'XXX' могут быть свои опции, с префиксом XXX_ЧЕГО_ТО_ТАМ.
DISABLE_XXX — универсальный формат макроса для всех проектов, условно говоря, в конфиге проекта пишем DISABLE_AAA, DISABLE_BBB, DISABLE_CCC — и сразу понятно, что фичи/либы 'AAA', 'BBB', 'CCC' отключены, понятно, что отключено (в смысле, что выкл), и понятно, что отключено ( в смысле, какая фича/либа).
Для фич, которые по умолчанию выключены, можно использовать макро ENABLE_XXX. В идеале, если пользователь фичи/библиотеки не хочет полагаться на умолчательное поведение, либа/фича должна обрабатывать как DISABLE_XXX, так и ENABLE_XXX, и проверять DISABLE_XXX и ENABLE_XXX на конфликтность.
В либах же, кроме отключения фич, могут быть и настройки каких-то опций, поэтому было бы логично сделать настроечные макро с именами вида XXX_*, где XXX — имя либы, а '*' — имя фичи и что делаем с ней — включаем/выключаем/как-то настраиваем.
Отдельно в прикладном проекте тоже могут быть какие-то настройки, их тоже было бы удобно настраивать через 'DISABLE_ФИЧА_ПРОЕКТА'.
Мне такая семантика вполне нравится, но, может, у кого-то есть 'контра' против такого подхода?
Пример:
Есть либа marty::BigInt для произвольной длины целых. Она умеет конвертировать marty::BigInt в marty::Decimal (и поэтому сама подключает соответствующие хидеры), но поддержку marty::Decimal в marty::BigInt можно отключить, задав макро DISABLE_MARTY_DECIMAL. Правда, это отключит marty::Decimal и по всему проекту, но я не очень понимаю, зачем в разных частях одного проекта так делать. Опции DISABLE_XXX/ENABLE_XXX предполагаются глобальными для проекта (конкретной цели, не обязательно для всего "solution").
Замечу, что раз либа marty::BigInt зависит от marty::Decimal, то обработать DISABLE_MARTY_DECIMAL/ENABLE_MARTY_DECIMAL должна она, как и их непротиворечивость.
Другой вариант — marty::Decimal сама обрабатывает DISABLE_MARTY_DECIMAL/ENABLE_MARTY_DECIMAL, и может подсовывать пустоту, если задан макрос DISABLE_MARTY_DECIMAL. Это удобно тем, что не надо самому в использующей marty::Decimal либе что-то проверять, но тогда надо безусловно инклюдить "marty_decimal/marty_decimal.h", а значит, тащить marty::Decimal в зависимости проекта, а этого хотелось бы избежать.
Есть либа marty::Decimal, она сама по себе, и ничего в ней отключать нет необходимости (но какими-то фичами было бы неплохо порулить через MARTY_DECIMAL_*, например: MARTY_DECIMAL_DEFAULT_PRECISION — количество десятичных знаков после запятой, которое будет использовано при делении — в остальных случаях точность не нужна).
Есть либа marty::format для форматирования, она поддерживает по умолчанию как marty::BigInt, так и marty::Decimal.
Она проверяет DISABLE_MARTY_DECIMAL/ENABLE_MARTY_DECIMAL, DISABLE_MARTY_BIGINT/ENABLE_MARTY_BIGINT на непротиворечивость, подключает при необходимости нужные хидеры, и имплементирует или нет необходимые фичи.
M>DISABLE_XXX — универсальный формат
Особенно универсально смотрится в узком комбобоксе.
Друга ищи не того, кто любезен с тобой, кто с тобой соглашается, а крепкого советника, кто полезного для тебя ищет и противится твоим необдуманным словам.
M>А зачем смотреть в узком комбобоксе? Смотри конфиги в текстовом редакторе
И не только в комбобоксе, это же касается контекстых меню в редакторе иходника, поиска с клавиатуры во всяких TreeView и т. п.
Иногда заставляют что-то делать в чужой программе, и её невозможно поменять.
Поэтому начинать идентификаторы с одинаковой повторяющейся части — плохая практика.
Друга ищи не того, кто любезен с тобой, кто с тобой соглашается, а крепкого советника, кто полезного для тебя ищет и противится твоим необдуманным словам.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, Нomunculus, Вы писали:
M>>>>DISABLE_XXX — универсальный формат O>>>Особенно универсально смотрится в узком комбобоксе.
Н>>При длинном XXX любая комбинация будет проблемой в узком комбобоксе
M>Ещё один про комбобокс... Вот откуда он взялся? И чем лучше в узком комбобоксе [MARTY_DECI]MAL_DISABLE, чем [DISABLE_MA]RTY_DECIMAL?
Я ж не тебе ответил, а ему. У него спрашивай что за комбобоксы у него
Есть подозрение, что в современных C++ных реалиях вся эта кухня с символами препроцессора DISABLE/ENABLE_XXX еще работает, когда все зависимости подключаются к проекту напрямую в виде исходников и вы полностью контролируете все параметры компиляции как проекта, так и всех его зависимостей.
Но вот когда в дело вступают инструменты вроде Conan и vcpkg, в которых библиотеки собираются с опциями, которые задает тот, кто опакечивает библиотеку, то все эти DISABLE/ENABLE_XXX могут стать палками в колесах. Не то, что бы обязательно будут, но могут.
Засунул кто-то вашу Marty::BigInt с неким ENABLE_XXX в vcpkg, а пользователь захотел задействовать DISABLE_XXX.
Особенно весело может быть когда в библиотеке в завсисимости от ENABLE_XXX меняются размеры каких-то полей у объектов.
Здравствуйте, so5team, Вы писали:
S>Есть подозрение, что в современных C++ных реалиях вся эта кухня с символами препроцессора DISABLE/ENABLE_XXX еще работает, когда все зависимости подключаются к проекту напрямую в виде исходников и вы полностью контролируете все параметры компиляции как проекта, так и всех его зависимостей.
Да
S>Но вот когда в дело вступают инструменты вроде Conan и vcpkg, в которых библиотеки собираются с опциями, которые задает тот, кто опакечивает библиотеку, то все эти DISABLE/ENABLE_XXX могут стать палками в колесах. Не то, что бы обязательно будут, но могут.
Да
S>Засунул кто-то вашу Marty::BigInt с неким ENABLE_XXX в vcpkg, а пользователь захотел задействовать DISABLE_XXX.
Без проблем, она у меня хидер-онли
S>Особенно весело может быть когда в библиотеке в завсисимости от ENABLE_XXX меняются размеры каких-то полей у объектов.
Да ничего особо интересного, всё то же самое.
И там нет предложения, как не настраивать библиотеки, а как управлять зависимостями библиотек, как это нужно мне
Здравствуйте, Marty, Вы писали:
M>В свои некоторые плюсовые либы и проекты хочу присунуть возможность отключать некоторые фичи при помощи препроцессора.
M>Напрашивается имя DISABLE_XXX, где 'XXX' — отключаемая фича или даже библиотека какая-то, со всеми её фичами.
можно не изобретать enable/disable, а сделать как многие делают в configure/makefile: USE_SSL, USE_ZIP, USE_CHATGPT, USE_STACKOVERFLOW. Можно делать и как в cmake, например: cmake /DUSE_CHATGPT=1 /DUSE_STACKOVERFLOW=1 /DUSE_OWN_BRAIN=0
Здравствуйте, RonWilson, Вы писали:
M>>В свои некоторые плюсовые либы и проекты хочу присунуть возможность отключать некоторые фичи при помощи препроцессора.
M>>Напрашивается имя DISABLE_XXX, где 'XXX' — отключаемая фича или даже библиотека какая-то, со всеми её фичами.
RW>можно не изобретать enable/disable, а сделать как многие делают в configure/makefile: USE_SSL, USE_ZIP, USE_CHATGPT, USE_STACKOVERFLOW. Можно делать и как в cmake, например: cmake /DUSE_CHATGPT=1 /DUSE_STACKOVERFLOW=1 /DUSE_OWN_BRAIN=0
Я думал об этом, но есть такой нюанс — я хочу по умолчанию использовать библиотеки, чтобы ничего не требовалось задавать вообще, и отключать уже тогда, когда их использование мешает пользователю — например, он хочет запихать либу в контроллер, и часть зависимых либ там не нужна или даже мешает.
Здравствуйте, Marty, Вы писали:
M>Я думал об этом, но есть такой нюанс — я хочу по умолчанию использовать библиотеки, чтобы ничего не требовалось задавать вообще, и отключать уже тогда, когда их использование мешает пользователю — например, он хочет запихать либу в контроллер, и часть зависимых либ там не нужна или даже мешает.
так никто же не мешает сделать в коде что-то вроде — будет по-умолчанию:
Здравствуйте, Marty, Вы писали:
S>>Использовать голову, как минимум.
M>Конкретно есть что сказать, или лишь бы что ляпнуть?
Есть: раз потенциально символы препроцессора могут вести к проблемам, то хорошо бы найти способ их вообще не использовать.
Например, если автоматическая конвертация marty::BigInt в marty::Decimal опциональна, то вынести это самую конвертацию куда-то отдельно. Хоть в отдельный заголовочный файл внутри marty::BigInt, хоть в отдельную библиотеку.
S>>Но судя по примерам говнокода, который можно у видеть у вас в репозиториях,
M>А что не так с кодом?
Местами он говно. Сопровождать такое можно пожелать только кровному врагу. Тащить такое к себе в проект с оглядкой на то, что если автор внезапно помрет от очередного ковида, то сопровождать придется самому не просто страшно, а очень страшно.
S>>с этим возможны разные варианты, в том числе и не самые оптимистические.
M>Давай, выкладывай
Варианты? Например, вы слишком сильно интеллектуально развиты, чтобы делать простые удобные вещи для простых людей. Вам не сложно написать и сопровождать шаблон функции на 700 строк. Значит ваша целевая аудитория такие же очень умные люди, как и вы, коих очень и очень мало.
Либо, напростив, вы недостаточно умны, чтобы понять, что не должно быть шаблона функции на 700 строк, и не смочь найти вариант от этого избавиться.
S>Есть: раз потенциально символы препроцессора могут вести к проблемам, то хорошо бы найти способ их вообще не использовать.
Пример проблемы можно?
S>Например, если автоматическая конвертация marty::BigInt в marty::Decimal опциональна, то вынести это самую конвертацию куда-то отдельно. Хоть в отдельный заголовочный файл внутри marty::BigInt, хоть в отдельную библиотеку.
Каким образом? Вполне допускаю, что я плохо знаю плюсы, но как сделать автоматическое преобразование без конструкторов и/или оператором приведения типа — я не знаю. И не вижу способа вынести преобразование за пределы класса
S>>>Но судя по примерам говнокода, который можно у видеть у вас в репозиториях,
M>>А что не так с кодом?
S>Местами он говно. Сопровождать такое можно пожелать только кровному врагу. Тащить такое к себе в проект с оглядкой на то, что если автор внезапно помрет от очередного ковида, то сопровождать придется самому не просто страшно, а очень страшно.
В чем проблема? Ну, если совсем тупой, то можно разок пройтись отладчиком, и всё станет понятно
S>Варианты? Например, вы слишком сильно интеллектуально развиты, чтобы делать простые удобные вещи для простых людей. Вам не сложно написать и сопровождать шаблон функции на 700 строк. Значит ваша целевая аудитория такие же очень умные люди, как и вы, коих очень и очень мало.
S>Либо, напростив, вы недостаточно умны, чтобы понять, что не должно быть шаблона функции на 700 строк, и не смочь найти вариант от этого избавиться.
S>Оба варианта так себе.
Не вижу особых проблем с функцией на 700 строк. Ещё претензии есть?
Здравствуйте, RonWilson, Вы писали:
M>>Я думал об этом, но есть такой нюанс — я хочу по умолчанию использовать библиотеки, чтобы ничего не требовалось задавать вообще, и отключать уже тогда, когда их использование мешает пользователю — например, он хочет запихать либу в контроллер, и часть зависимых либ там не нужна или даже мешает.
RW>так никто же не мешает сделать в коде что-то вроде — будет по-умолчанию: RW>
Здравствуйте, Marty, Вы писали:
M>>>А что не так с кодом?
S>>Местами он говно. Сопровождать такое можно пожелать только кровному врагу. Тащить такое к себе в проект с оглядкой на то, что если автор внезапно помрет от очередного ковида, то сопровождать придется самому не просто страшно, а очень страшно.
M>В чем проблема?
В сложности.
M>Ну, если совсем тупой
то проще послать тов.Marty вдоль как с его разработками, так и с просьбой придумать как ему поступать в его разработках.
M>Не вижу особых проблем с функцией на 700 строк.
Здравствуйте, Marty, Вы писали:
M>Здравствуйте, RonWilson, Вы писали:
RW>>давно на Сы не писал, ну как-то так см. OPENSSL_NO_ENGINE
M>Ну так это и получается ровно то, что я предлагаю, только в моей нотации это будет выгладеть как M>DISABLE_OPENSSL_ENGINE/OPENSSL_ENGINE_DISABLE
зачем это DISABLE? WITH_SSL, USE_HIGH_COMPRESSION, NO_MOVE_CTORS и так далее — сразу и по сути, без этих enable/disable/default
Здравствуйте, RonWilson, Вы писали:
RW>>>давно на Сы не писал, ну как-то так см. OPENSSL_NO_ENGINE
M>>Ну так это и получается ровно то, что я предлагаю, только в моей нотации это будет выгладеть как M>>DISABLE_OPENSSL_ENGINE/OPENSSL_ENGINE_DISABLE
RW>зачем это DISABLE? WITH_SSL, USE_HIGH_COMPRESSION, NO_MOVE_CTORS и так далее — сразу и по сути, без этих enable/disable/default
Да похрен, DISABLE или NO. Можно писать USE_XXX/NO_XXX — это не так counterpart, как ENABLE_XXX/DISABLE_XXX, но пофик. Просто хочу выработать единое для себя соглашение, чтобы не было чехарды в разных места
Здравствуйте, Marty, Вы писали:
M>Да похрен, DISABLE или NO. Можно писать USE_XXX/NO_XXX — это не так counterpart, как ENABLE_XXX/DISABLE_XXX, но пофик. Просто хочу выработать единое для себя соглашение, чтобы не было чехарды в разных места
ну тогда уж ENABLE/DISABLE_FEATURE_000045 и табличку с фичами, будет единообразно
Здравствуйте, RonWilson, Вы писали:
M>>Да похрен, DISABLE или NO. Можно писать USE_XXX/NO_XXX — это не так counterpart, как ENABLE_XXX/DISABLE_XXX, но пофик. Просто хочу выработать единое для себя соглашение, чтобы не было чехарды в разных места
RW>ну тогда уж ENABLE/DISABLE_FEATURE_000045 и табличку с фичами, будет единообразно
Здравствуйте, pilgrim_, Вы писали:
M>>Не понял, получается, что USE_HUMAN_BRAIN включен всегда, чтобы ты в опциях сборки не задал
_>3 состояния: _>1) USE_HUMAN_BRAIN не определён — используется настройка по умолчанию (значение 0 или 1) _>2) Определён с USE_HUMAN_BRAIN = 0 — отключено _>3) Определён с USE_HUMAN_BRAIN = 1 — включено
Да, так получается, согласен. Просто как-то привык проверять наличие определенного макроса, а не наличие и его значение