Комментарии 427
// 1
template <typename T>
requires Copyable<T>()
void foo(T x);
// 2
template <Copyable T>
void foo(T x);
// 3
void foo(Copyable x);
А есть ли возможность сделать перегрузки constexpr/runtime для функций? Отсутствие этой фичи не позволяет считать на этапе компиляции многие математические функции, в т.ч. exp/log.
Какой статус у Ranges?
Варианты 2 и 3 активно обсуждаются и полируются, в них есть проблемы:
- Вариант 2 не позволяет работать с концептами принимающими сразу два шаблонных параметра
- Вариант 3 вызывает недоумение в случае
Типы у переменных x и y должны быть одинаковые или нет?void foo(Copyable x, Copyable н);
А есть ли возможность сделать перегрузки constexpr/runtime для функций?
Идёт работа над волшебной функцией is_constant_evalueated(). Она позволит внутри функции делать ветвление, в зависимости от того, выполняется функция на рантайме или на этапе компиляции:
constexpr double power(double b, int x) {
if (std::is_constant_evaluated() && x >= 0) {
// A constant-evaluation context: Use a
// constexpr-friendly algorithm.
double r = 1.0, p = b;
unsigned u = (unsigned)x;
while (u != 0) {
if (u & 1) r *= p;
u /= 2;
p *= p;
}
return r;
} else {
// Let the code generator figure it out.
return std::pow(b, (double)x);
}
}
Какой статус у Ranges?
Идёт активная работа по принятию из в C++20. Есть все шансы на успех.
Вариант 2 не позволяет работать с концептами принимающими сразу два шаблонных параметра
это критично с точки зрения РГ даже с учетом того, что для этого есть fallback синтаксис?
Типы у переменных x и y должны быть одинаковые или нет?
(мне) очевидно, что нет. Неужели это является решающим фактором?
Кому-то не нравится вариант 3, так как из сигнатуры функции не понятно что это шаблонная функция (нужно знать, что Copyable — это концепт; проблем не возникает в случае со стандартными концептами, однако для больших кодовых баз со множеством своих концептов разобраться будет намного сложнее).
Кому-то не нравится вариант 2, потому что он громоздкий :)
Про модули и сопрограммы что-то известно? Herb Sutter даёт прогноз, что сопрограммы скорее всего войдут, а насчёт модулей нет ясности.
Буквально 2 заседания назад появилось новое предложение по модулям, позволяющее экспортировать макросы и упрощающее миграцию старого кода на модули. На ближайших заседаниях будут пытаться слепить старые и новые предложения в одно. Общее предложение скорее всего будет сначала выкачено в эксперимент (в виде обновленного Modules TS), и только после этого смержено в стандарт. В общем, шансы увидеть модули в C++20 есть, но они не велики.
Сопрограммы скорее всего войдут в C++20. Были попытки выдвинуть другое (конкурирующее) предложение по сопрограммам. Поддержки новый подход не получил. Если новых предложений или возражений не поступит, то Coroutines TS окажется в C++20.
Ряду компаний очень не понравилось отсутствие макросов и, как следствие, невозможность «модуляризировать» системные заголовочные файлы.
Или я просто не знаю, как, но что-то сомневаюсь.
#define EXEC_ON_SCOPE_EXIT auto CONCAT_EXPANDED_ARGUMENTS_2(scope_exit_executor_, __LINE__) = detail::makeOnScopeExitExecutor
В общем случае, макросы, использующие стрингификацию и/или конкатенацию строк, обычно решают задачи, не решаемые средствами С++.
en.cppreference.com/w/cpp/experimental/source_location
Пока есть только в gcc
static constexpr volatile uint32_t* MY_PTR = (volatile uint32_t*)0x12345678;
А без этого невозможен никакой embedded и низкоуровневое системное программирование. Приходится всё только на многоуровневых извращённых макросах делать.
Колоссальный косяк, кстати, который не позволяет писать под железо на полноценных плюсах. А всё потому, что бородатые дядьки опять заигрались в стандарты.
Я читал про эксперимент на модулях от clang (а авторы proposal наверняка вдохновлялись и такими модулями), они давали прирост 60% (или 10% по сравнению с использованием precompiled headers).
Хочется еще узнать, а как реализованы Modules TS и ATOM в gcc. Используют ли они предложенное Страуструпом бинарное представление пропарсенного C++ кода? Или у них какое-то свое представление? И таскают ли в реализации ATOM текстовую копию кода для поддержки экспорта макросов?
Один из разработчиков Modules TS утверждает, что макросы — одна из основных причин тормозов. Поэтому пока вы не начнёте использовать модели без макросов — довольствуйтесь 10% прироста скорости.
Лично мне ATOM нравится простотой внедрения в большие кодовые базы, и не нравится своим небольшим приростом скорости компиляции.
Modules TS и ATOM в gcc сделаны и информация об актуальном состоянии есть вот тут gcc.gnu.org/wiki/cxx-modules
Может подход в духе precompiled headers и достигает теоретического предела в приросте?
Я ни в коем случае не защищаю макросы и не пишу своих в кодовой базе. Я заинтересован в том, чтобы разработчики библиотек активно переходили на модули, но как бы не получилось так, что будем еще 10 лет разрабатывать модули, а потом 10 лет переходить на них.
Возможно, моя русская терминология неточна: она формировалась в 90 годы прошлого века во время чтения сделанных издательством «Мир» переводов классических англоязычных руководств по C и С++. Имеется в виду тот факт, что язык C++ работает с отдельными единицами компиляции, превращая их в объектные файлы определенного для целевой платформы формата (с функциями и глобальными переменными). Этот формат, соглашения о вызовах и ABI, устройство выполнимых бинарных образов и разделяемых библиотек, строго говоря, к языку C++ не относится, а относится к целевой платформе и в основных чертах остается неизменными со времени изобретения ассемблера. В частности, часть платформы — компоновщик, перебирает указанные ему объектные файлы, смотрит, на какие имена внешних объектов они ссылаются и найденные объекты (тела функций и определения глобальных переменных) как-то платформозависимо укладывает в выполнимый файл. Если компоновщик не найдет нужный объект — будет ошибка времени компоновки.
Противоположностью этому являются варианты явной компоновки, когда компилятор формирует бинарные файлы не только со скомпилированным кодом, но и с мета-информацией о видимых снаружи именах. Такие файлы и называются (обычно) модулями. В единице компиляции требуется указывать не только имя внешней сущности (функции или переменной), но и то, из какого модуля ее следует брать. В этом случае компоновщик не ищет первое попавшееся имя, а ищет конкретный объект в конкретном модуле, что и быстрее, и «типобезопаснее». Примеры — Turbo Pascal и Modula2, C#, можно продолжить.
Совместимость с C и используемый в C (взятый из экосистемы ассемблера) инструментарий — совершенно сознательное решение Страуструпа, сделанное при создании C++. По моему мнению, это решение сыграло важнейшую роль в том взрывном распространении C++, которое мы наблюдали в 90 годы XX столетия))).
И мне не очень понятно, где тут место для сколь-нибудь развитой системы модулей. Опасаюсь, что в результате такого «скрещивания ужа с ежом» получится нечто, что будет смотреться столь же органично, как седло на корове или пятая нога у собаки. Впрочем, это мое личное мнение и я его никому не навязываю.
Насколько я понимаю, в модулях единицей трансляции является не файл, а множество файлов — модули. Это, скорее всего, и даёт весь профит. И это нужно учитывать при сравнении.
Когда вы собираете проект, каждый cpp файл может компилироваться параллельно (это хорошо, отличная масштабируемость).
Вы верно написали про раздувание на 1к1к строк. Дополнительной проблемой является то, что макросы из одного заголовочного файла могут влиять на содержимое другого заголовочного файла. Из-за этого компилятор не может кешировать разобранные заголовочные файлы, так как при изменении порядка инклюдов может поменяться их содержимое.
Ещё одна проблема — невероятно количество макросов (они пораждаются например include guards). Держать их всех в памяти и препроцессировать документ становится тяжёлой задачей.
Модуль — это набор файлов, собранных воедино и сохранённых на диск в понятном для компилятора бинарном виде. Таким образом, при подключении модуля, компилятор просто считает его с диска в свои внутренние структуры данных (минуя этапы открытия нескольких файлов, парсинга, препроцессинга и некоторых других вспомогательных вещей).
Если модуль не экспортирует макросы, то сильно упрощается препроцессирование последующих заголовочных файлов и вашего кода. Так же уменьшается количество оперативы, требуемой для хранения макросов и для сообщения об ошибке (нет макросов — нет необходимости запоминать код перед препроцессированием)
Дополнительный прирост скорости при компиляции будет получен за счёт того, что в модуле вы явно указываете его публичный интерфейс. То есть компилятор сможет сделать ряд оптимизаций ещё при создании модуля. Это сильно уменьшит затраты оперативной памяти, ускорит поиск подходящих перегруженных функций, структур и т.п за счёт того, что их будет просто меньше.
И наконец, финальная стадия сборки проекта — линковка. В данный момент линковщик много времени тратит на выкидывание одинаковых блоков скомпилированного кода (вы подключили <string> 100 раз — линкер выкинет 99 скомпилированных std::string). С модулями линкеру не придется этим заниматься, т.к. файл модуля не будет вкомпиливаться внутрь собранного cpp файла.
Но при этом НЕ ускоряется стадия оптимизации вашего кода. Если большую чать времени компилятор оптимизирует вашу программу — большого ускорения компиляции не ждите.
минуя этапы открытия нескольких файлов, парсинга, препроцессинга и некоторых других вспомогательных вещей
Когда-то пытался измерить — всегда получал очень малый вклад этих стадий во время компиляции.
Но при этом НЕ ускоряется стадия оптимизации вашего кода. Если большую чать времени компилятор оптимизирует вашу программу — большого ускорения компиляции не ждите
Оно одновременно и замедляет и ускоряет. Замедляет за счёт того, что происходит более глобальный ipo, а ускоряет за счёт того, что не нужно 10раз оптимизировать одни и те же функции в контексте того же header-only, которого в С++ предостаточно.
Если модуль не экспортирует макросы, то сильно упрощается препроцессирование последующих заголовочных файлов и вашего кода.
Макросы так же засирают глобальный неймспейс.
Если модули позволят перевести весь легаси-код в модули из которых не будут торчать сишные кишки, макросы и тому подобное — это будет прекрасно. Для чего же они современному коду, особенно если использовать модные/набирающие популярность техники, я не понимаю.
И сразу открытый вопрос: а почему нельзя совместить оба подхода, с экспортом макросов и без? Даже если модуль с макросами будет собираться дольше, пусть это будет опцией при сборке модуля. Если опция не включена, то и хранить модуль можно в более оптимальном виде, и знать можно, что он не повляет на последующие текстовые инклюды. Дескать, если разработчик настолько сильно желает экспортировать макросы в своем апи, что готов пожертвовать временем компиляции у конечных потребителей — пусть. Пользователям решать, использовать такую библиотеку или нет.
Да и на сервере, не так чтобы сильно ускоряется сборка. Я делал такую штуку — в cmake делал автоматическое объединение cpp всей цели для одной либы. Ускорение — не больше, чем в два раза. И плюс мы получаем тьму неудобств от необходимости следить за анонимными неймспейсами и т.п.
Если еще и локально одна схема, а на билде другая — это вообще адъ.
Пока лично для меня самая эффективная схема — распределенная сборка) Железо докупить оказывается дешевле. Когда сборка параллелится на 100+ ядер — ускорение налицо. Понятно, что и там есть ограничение сверху (возможность параллелить, возможности сети), но зато эффектом можно пользоваться и на CI, и на дев машине.
Я пока раздумываю как в свою систему распределённой сборки модули прикручивать. Получается, что по сети не только единицу трансляции гонять придется, но и все используемые скомпиленные модули.
Распределенную сборку они тоже пробовали — не взлетело, слишком медленно. Полагаю, что уперлись в wifi сетку.
Но мой поинт в другом. Модули по своей сути могут отчасти напоминать идею unity билдов. Предобработать исходники, объединить их в удобном виде и закешировать — и последующая компиляция будет быстрой.
Офисную сеть для разработчиков делать целиком на вайфае — омг) Ну у нас есть те кто с ноутбуков компилят, ускорение все равно значительное.
«скорость инкрементного билда их не раздражает» — какие спокойные разработчики! Лично меня цикл сборка-запуск больше 5 секунд начинает заметно напрягать, а 15 — откровенно раздражать.
Модули еще по идее и линковку должны ускорять нехило, т.к. не будет определений одного и того же в каждой оттранслированной единице.
Я думаю идеальный вариант для меня через пять лет — модули + распределённая сборка.
Ну и компоновка всего проекта как кучи статичных либ — вообще сомнительное удовольствие)
С юнити билдами кроме скорости сборки, повторюсь, лично для нас основная проблема — конфликт имен (и иногда хедеров). Считай, прощай уютный анонимный неймспейс.
По хедерам — допустим есть либа, которая оборачивает два сторонних API, предоставляя общий интерфейс. По отдельности хедеры собираются норм, а когда компилишь вместе — хедеры реализаций начинают конфликтовать.
Ах да, еще замечательное — т.к. все файлы идут вместе, начинает теряться необходимый набор хедеров в каждой единице трансляции. Начинаются вещи вроде «убрали один cpp файл — все отвалилось», а файл этот может исключаться из сборки какой-то опцией, т.е. нужно тестировать все комбинации опций при вообще любой правке, даже не в хедерах.
В общем, в плане поддержки это очень тяжело. От распределённой сборки все же треба только железо/сеть, ты никак не думаешь о каком-то специфичном коде.
Если рассуждать о скорости компиляции, то модули подступаются к этому вопросу с нескольких сторон.
Например в случае, если не экспортим макросы, то единицей модуля может быть единица трансляции после фаз трансляции 1-7(8), представленная в оптимальном бинарном виде. Согласитесь, если вам вместо файла с исходниками дадут вот такую единицу модуля — компилироваться все в итоговый файл будет быстрее.
Или, например, объявление модуля. Не знаю, как там после последней встречи объединили Modules TS и ATOM, но конкретно от ATOM ранее было предложение разрешать объявление модуля только на верху единицы трансляции. Это позволит компилятору прочесть только заголовки файлов и построить граф зависимостей между файлами, чтобы потом оптимальнее подгружать их при компиляции.
Другой момент касается шаринга явных и неявных инстанцирований шаблонов: в модулях их стараются расшаривать по-максимому, чтобы не делать повторно одни и те же инстанцирования. Я правда не знаю, как современные компиляторы работают с инстанцированиями — пытаются ли запоминать, что какой-то шаблон уже обрабатывали и инстанцировали в другой единице трансляции? Если нет, то здесь модули так же дадут ускорение, т.к. это одно из главных вкладов во время компиляции.
Zapcc делает именно это — кэширует инстанциации между ТУ. Для этого они держат в памяти сервер с кэшем.
Согласитесь, если вам вместо файла с исходниками дадут вот такую единицу модуля — компилироваться все в итоговый файл будет быстрее.
Это даёт свои проблемы. Мы потеряем то самое преимущество, особенно в контексте header-only, когда мы всегда можем увидеть как минимум сигнатуры функций. Очень сомневаюсь, что модули дадут указанный выше побочный эффект.
Выше я уже писал, что не получал особого профита от тех же pch. Может на обычных инклюдах с одними декларациями это и даёт что-то, но это уже давно не модно.
Опять же, один из тех же профитов, который даёт header-only — простую кросскомпиляцию и между платформами и между компиляторами. Дадут ли тоже самое модули? Сомневаюсь.
Если нет, то здесь модули так же дадут ускорение, т.к. это одно из главных вкладов во время компиляции.
Поэтому совместно с шаблонами используется header-only подход.
Мы потеряем то самое преимущество, особенно в контексте header-only, когда мы всегда можем увидеть как минимум сигнатуры функций.
Не совсем понял. Под «увидеть» понимается посмотреть на код в human-readable формате? Если да, то вопрос тулчейна, он должен научиться показывать интерфейс модуля в читаемом виде, все необходимое для этого в модуле есть.
Опять же, один из тех же профитов, который даёт header-only — простую кросскомпиляцию и между платформами и между компиляторами. Дадут ли тоже самое модули? Сомневаюсь.
Какая связь между кроссплатформенностью и header-only? Как в header-only спокойно можно писать непереносимый код, так и не в header-only можно писать кроссплатформенно. Это ортогональные понятия.
Если да, то вопрос тулчейна
И текущие реализации модулей это умеют? Как это должно быть реализовано? В ситуации с хедерами всё понятно — я открыл файл и прочитал( в самом примитивном случае). Что же будет делать тулчейн? Создавать файлы, которые будут эмулировать хедеры, перекладывать это на шею ide?
Какая связь между кроссплатформенностью и header-only?
Прямая.
Как в header-only спокойно можно писать непереносимый код, так и не в header-only можно писать кроссплатформенно.
Дело не в этом. Нельзя просто так взять и собрать одну часть одним, а другую часть вторым компилятором. Т.е. бинари теряют вообще какой-то смысл по части дистрибуции, надо будет опять всё собирать.
Опять же, самая сложная проблема — собрать всё, собрать все зависимости. Дефолтный подход требует системы сборки, где добиться кроссплатформенной сборки — то ещё приключение. Даже не смотря на модный нынче cmake, и попытки создавать пакетные менеджеры.
Опять же, базовый подход очень любит тянуть зависимости, которые так же нужно собрать. Проблемы с поиском зависимостей.
Далее, дистрибуция. Это опять приключения. Нужна статическая линковка, либо приключения с контейнерами. Статическая линкова сама по себе то ещё приключение и мало кто её поддерживает из зависимостей.
В случае же с header-only нет никаких проблем с дистрибуцией самих зависимостей — просто носишь собой/забираешь из vcs. Нет никаких проблем со сборкой — нет никакой сборки вообще. Нет никаких проблем с дальнейшей дистрибуцией бинарей — нет никаких бинарные зависимостей, линковки и прочих приключений
Создавать файлы, которые будут эмулировать хедеры, перекладывать это на шею ide?
Почему бы и нет? Либо просто показывать интерфейс в менюшке автокомплита, как это делается во многих ide сейчас?
Нельзя просто так взять и собрать одну часть одним, а другую часть вторым компилятором.
Далее, дистрибуция. Это опять приключения. Нужна статическая линковка, либо приключения с контейнерами.
Если думать о дистрибуции бинарного представления модулей, то беспокоиться нужно будет только о том, чтобы бинари модулей-зависимостей были от того же / совместимого компилятора. Пляски с линковкой отпадают.
Если и о компиляторах думать не хочется, можно распространять только исходники и собирать их самостоятельно в модули, в любом случае соберутся быстрее старого подхода. header-only библиотека ортогональна простоте сборки: у неё точно так же могут быть зависимости, которые потребуется собрать, у неё могут особые требования на флаги компиляции, которые желательно носить рядом, в том же cmake. Хорошие header-only либы этими проблемами не страдают, ну так и модули можно писать точно так же, избегая сложных зависимостей и сложной сборки.
Почему бы и нет? Либо просто показывать интерфейс в менюшке автокомплита, как это делается во многих ide сейчас?
Интерфейс мало кому нужен, к тому же было проигнорировано множество тезисов, как и множество деталей.
В подсказке описание типа/класса тоже можно показать? Да и сигнатуру функции, особенно с какими-то концептами, контрактами и прочим. Где это всё показывать? И в каком виде? В виде кода?
Опять же, куда девать коменты — нужно ещё и это эмулировать.
Так же, я говорил не только о сигнатурах, но и о самих исходниках, которые всегда и удобно доступны в ситуации использования header-only.
Если думать о дистрибуции бинарного представления модулей, то беспокоиться нужно будет только о том, чтобы бинари модулей-зависимостей были от того же / совместимого компилятора.
Проблема в том, что в ситуации с header-only думать не нужно. И пока это лишь фантазии, а я сравнивал реальность. Я утверждал, что модули дают профит по части кросскомпиляции и задавал вопрос, а дадут ли тот же профит модули? Я не сравнивал модули и header-only. Был вероломно подменён тезис, что очень некрасиво.
Если и о компиляторах думать не хочется, можно распространять только исходники и собирать их самостоятельно в модули, в любом случае соберутся быстрее старого подхода.
Про старый подход я и не говорил. В контексте же правильного header-only не существует всех тех проблем, которые и дают модулям какой-то профит.
header-only библиотека ортогональна простоте сборки
Header-only предполагает header-only, и это очевидно. Если header-only тянет какие-то левые бинарные зависимости — это уже не header-only.
у неё точно так же могут быть зависимости, которые потребуется собрать
Header-only зависимости не нужно собирать.
у неё могут особые требования на флаги компиляции, которые желательно носить рядом
Флаги компиляции чего? У меня такое чувство, что вы мало знакомы с темой, очень мало. Header-only это встраиваемая зависимость, она не собирается — она собирается в контексте вашего кода. Для неё не может быть каких-то отдельных флагов для cmake — они будут накладываться на всё то, куда вы это заинклюдили. И если это «куда» является так же header-only, то инклюдится это ТОЛЬКО в ОДНО место, а значит флаги всегда ОДНИ.
К тому же, у стандартного кода может быть только один флаг — это std, который совместим сверху вниз, а значит в любом случае код использующий header-only зависимость нужно собирать с std не ниже необходимого для зависимости.
ну так и модули можно писать точно так же, избегая сложных зависимостей и сложной сборки.
Модули — это уже лишние телодвижения. При этом уже нужна какая-то система сборки, уже нужно будет делать всё тоже, что и
при header-only, только с куда большим набором заморочек. При этом просто в голословное «можно» я поверить не могу.
Модули для леги кода? Да. Модули для блобов? Да. Преимущества очевидны, а вот в сравнение с современными техниками — преимущества очень не очевидны, по крайней мере мне.
У меня такое чувство, что вы мало знакомы с темой, очень мало.
Может, не стоит скатываться в обвинения о непрофессионализме? Это оскорбительно и лишь провоцирует на взаимные обвинения.
Давайте лучше почитаем proposals по модулям и предположим, как эти предложения смогут реализовать компиляторы. А для начала договоримся об одном понимании header-only библиотек, какие "гарантии" они дают, а какие — нет.
К тому же, у стандартного кода может быть только один флаг — это std, который совместим сверху вниз, а значит в любом случае код использующий header-only зависимость нужно собирать с std не ниже необходимого для зависимости.
Предположим, я пишу проект на последнем C++17 и подключаю к нему header-only библиотеку, которая:
- Использует в своей реализации старенький std::bind1st. Эта вещь была удалена в 17 плюсах. Gcc спокойно скомпилирует заинклюженную в мои cpp файлы эту header-only библиотеку. Clang тоже. Но только если будет использоваться std либа от gcc. Если я подключу std от clang, то получу ошибку — там эта вещь была удалена в соответствии со стандартом. Флаг std не совместим сверху вниз, в нашем примере он навязывается проекту от header-only либы, иначе проект не соберется только из-за несборки кода header-only библиотеки.
- Использует чуть более современный std::thread. Чтобы мой проект собрался с этой header-only либой на линуксе, я должен слинковаться с pthread.
- Использует std::filesystem. Тогда на компиляторе gcc я должен слинковаться с stdc++fs.
Вывод: header-only библиотека может зависеть от бинарей даже в случае, если используется только стандартный c++.
А теперь о том, какие же "гарантии" дает header-only либа. А она гарантирует лишь:
- что все необходимые файлы с реализацией будут автоматически подключены в конечный cpp файл;
- если какая-то часть библиотеки не используется в конечных cpp файлах, она туда не подключается и соответственно не собирается, ускоряя сборку;
А так же гарантирует минусы:
- включая в себя все необходимые файлы с реализацией, соответствующий заголовок при включении в конечные cpp файлы будут требовать разбора/инстанцирования/компиляции одного и того же кода раз за разом в каждом cpp файле.
- Сделает видимым конечному потребителю все детали реализации, давая возможность заиспользовать то, что не должно быть использовано напрямую.
Способ, которым компилятор ищет подключаемые заголовочные файлы — implementation defined. В простом, но очень некрасивом случае, подключаемую библиотеку можно положить рядом с своим исходным кодом и она будет найдена при инклюде без лишних телодвижений. В общем же случае необходимо передать компилятору с помощью директивы директории, где искать подключаемые заголовки.
И почему вообще header-only библиотеки вы называете "современным" подходом? Что в этом современного? Его разве изобрели пару лет назад?
Неужели эти "гарантии" не смогут предоставить модули?
Способ поиска модуля при импорте — implementation defined. Компилятор точно так же может сделать директиву, где будет принимать директорию для поиска подключаемых модулей.
В случае, если будет принято предложение ATOM об объявлении модуля только на верху файла, тогда компилятору будет достаточно прочесть заголовки всех файлов в этой директории, чтобы понять, что потребует сборки. Это не так быстро, как чтение хедера по прямому пути из инклюда, но выполняется однократно, в отличии от многократного чтения хедера при каждом включении. Если предложении от ATOM не будет принято, компилятору придется прочесть/распарсить каждый файл целиком, чтобы найти там объявления модуля. Это соответственно дольше.
Всё! Гарантии header-only либы могут быть соблюдены и модулями! При этом они лишены недостатоков header-only либы — вся внутренняя реализация библиотеки не будет видна конечному коду и будет компилироваться только один раз.
И это все для случая дистрибуции только исходников модуля. В случае дистрибуции их бинарного представления будет больше работы по учету платформы сборки, но этой работы будет априори меньше, чем при дистрибуции финальных бинарей библиотек.
Использует в своей реализации старенький std::bind1st. Эта вещь была удалена в 17 плюсах. Gcc спокойно скомпилирует заинклюженную в мои cpp файлы эту header-only библиотеку. Clang тоже. Но только если будет использоваться std либа от gcc. Если я подключу std от clang, то получу ошибку — там эта вещь была удалена в соответствии со стандартом. Флаг std не совместим сверху вниз, в нашем примере он навязывается проекту от header-only либы, иначе проект не соберется только из-за несборки кода header-only библиотеки.
Вы утверждали, что нужны какие-то флаги(отдельные) отдельно для header-only, на что я вам ответил — никаких отдельных флагов нет, а всё, что может наложить header-only на ваш код — это std.
Опять же, что из текста выше должно следовать? То, что вы взяли библиотеку, которая несовместима с вашим компилятором? Ну дак это никакого отношения к теме не имеет. Аналогичное будет в любом другом случае.
По поводу «навязывается» — я уже об этом говорил, в любом случае он навязывается.
По поводу совместимости — оно всё совместимо, а ссылаться на 1-2 исключения имеет мало смысла, которые, к тому же, мало кто использовал и которые выпиливаются банальным реплейсом.
Использует чуть более современный std::thread. Чтобы мой проект собрался с этой header-only либой на линуксе, я должен слинковаться с pthread.
Будь она какой угодно — вам нужно будет линковаться с pthread.
Вывод: header-only библиотека может зависеть от бинарей даже в случае, если используется только стандартный c++.
Очевидно, что стандартные зависимости мало кого волнуют, ведь они стандартные. О них никто и не говорил, их никто не учитывает. Если что-то требует с++17 — обеспечьте это. -pthread, -lstdc++fs — это всё заморочки конкретного компилятора/платформы.
К тому же, я всё это заранее проговаривал:
Если header-only тянет какие-то левые бинарные зависимости — это уже не header-only.
Я уточнял и про левые зависимости, и про то, что header-only может их тянуть, и про то, что я не считаю подобное header-only.
включая в себя все необходимые файлы с реализацией, соответствующий заголовок при включении в конечные cpp файлы будут требовать разбора/инстанцирования/компиляции одного и того же кода раз за разом в каждом cpp файле.
Это не проблема, организуйте нормальную(модульную) сборку. К тому же, ничего не мешает организовать в проекте подобное и без сборки. Разделите проект на header-only модули. Он будет работать и собираться быстрее.
У такого подхода есть одна проблема — компилятор не сможет собрать модуль в сто миллионов строк кода, но подобная проблема будет и в самих модулей в случае, если единицей трансляции является модуль.
Да, тут может быть некая проблема с большой время сборки модуля, что будет не особо удобно. Но это проблема плохого дизайна и она может проявится и без header-only, правда зачастую в меньшем масштабе.
Сделает видимым конечному потребителю все детали реализации, давая возможность заиспользовать то, что не должно быть использовано напрямую.
Это просто придирки. Таких проблем ни у кого нет, а если кому-то нужно что-то заиспользовать — он заиспользует это и реализация «отдельно» ему никак не помешает.
Способ, которым компилятор ищет подключаемые заголовочные файлы — implementation defined. В простом, но очень некрасивом случае, подключаемую библиотеку можно положить рядом с своим исходным кодом и она будет найдена при инклюде без лишних телодвижений. В общем же случае необходимо передать компилятору с помощью директивы директории, где искать подключаемые заголовки.
Такая же придирка, как и в случае выше. Простой пример /usr/include? Инклюды обладают очень простым свойством — их можно накидать куда угодно и использовать, язык это умеет.
И если что-то и нужно передавать — это корневой каталог по типу /usr/include и не более того. И даже если это какая-то сложная иерархия, то они организуется из любого thrid_payty без каких-либо проблем.
В сравнении с тем, что нужно сделать в ситуации со сборкой — это 1 против 100.
И почему вообще header-only библиотеки вы называете «современным» подходом? Что в этом современного? Его разве изобрели пару лет назад?
Изобрели их дано, массовым явление стало достаточно недавно.
В современных реалиях «старый» подход оправдан очень в малом кол-ве случаев. И в противовес старому подходу я называю header-only новым подходом.
Неужели эти «гарантии» не смогут предоставить модули?
Способ поиска модуля при импорте — implementation defined.
Если бы они сделали инкрементальную сборку, то это да — даст очень большой профит. Что ещё даст какой-то профит — я не знаю.
В случае, если будет принято предложение ATOM об объявлении модуля только на верху файла, тогда компилятору будет достаточно прочесть заголовки всех файлов в этой директории, чтобы понять, что потребует сборки. Это не так быстро, как чтение хедера по прямому пути из инклюда, но выполняется однократно, в отличии от многократного чтения хедера при каждом включении.
Меня не особо радуют всякие ограничения про «вверху файла». К тому же, одно дело «может», а другое дело «делает».
Всё! Гарантии header-only либы могут быть соблюдены и модулями! При этом они лишены недостатоков header-only либы — вся внутренняя реализация библиотеки не будет видна конечному коду и будет компилироваться только один раз.
Очень сомнительно, что компилятор сможет взять точку входа(файл) и построить все модули без костылей. Потребуется система сборка, что уже минус.
Опять же, «внутренняя реализация видна» — для меня является не минусом, а плюсом. Никакого минуса я тут не вижу вообще.
По поводу «компилироваться» — это недостаток по части оптимизации. Это будет очередная линковка. Если же это не линковка, то компиляция будет, а модуль будет просто частично скомпилирован( и то, лишь в теории).
В конце концов, столько времени потратить на то, чтобы минимизировать влияние препроцессора на время компиляции, и опять мы суём макросы, чтобы увеличить влияние препроцессора на время компиляции… зачем?
Ну и не стоит так надеяться на модули, в 10 раз они компиляцию не ускорят (в ближайшее время).
Ускорят.Боюсь, будет сильно зависеть от кода. По опыту работы с некоторыми header-only библиотеками получается, что иногда львиная доля времени во время компиляции уходит на инстанцирование и оптимизацию шаблонов, а не на загрузку и обработку заголовочных файлов.
Пример использования:
constexpr auto re = "^(?:[abc]|xyz).+$"_pre;
re.match(some_string);
* генерацию парсеров из EBNF и других форматов описания грамматик
* ORM классов из коробки
* сигнал/слоты Qt без макросов
* расцвет DSL
* красивый RPC
* ???
сигнал/слоты Qt без макросов
github.com/woboq/verdigris
У автора в блоге (https://woboq.com/blog/), кстати, много всего интересного написано про нестандартное использование C++.
В принципе почти хватает и сейчас, без метапрограммирования
Я вместо if(!result) пишу if (result == false), ибо восклицательный знак легко теряется из виду.
Может стоит дать другое имя?
И будут ли весь math модуль делать constexpr? Мне бы не помешал constexpr синус и косинус.
Да и может быть стоило бы всё-таки сделать какой-нибудь «std2»?
Ещё одно занятное изменение, которое рассматривается для приёма в C++20 — это constexpr! функции.
Я когда прочитал это предложение, то не понял в тот же миг, что оно говорит о чем-то новом)
Я уж молчу про то, как легко слово «констекспр» произносится вслух -_-' Но говорить вслух «констекспр!» будет вообще невозможно.
«Констекспрбанг»? «Констэкспр экскламейшн марк»? «Констэкспр восклицательный знак»?
Гуглить тоже очень тяжело будет.
Это всё мне напоминает чемодан, который с каждым годом становится всё дырявее и дырявее, а его выкинуть жалко, поэтому дырки латают и красят новым модным цветом.
Да все контейнеры (также их итераторы) и алгоритмы будут гораздо проще и выразительнее с концептами и с учётом существования compile-time выражений почти всё можно переписать и сделать чище.
При этом всём не нужно выкидывать старую библиотеку (дабы всеми необходимая обратная совместимость осталась). Но и развивать старую библиотеку я не вижу смысла.
Такой потенциал теряем…
Я понимаю, что я как-то сегодня прилично так умничаю, но просто мне кажется, что для молодых специалистов (как и я) был бы C++ более привлекателен с подобной новой и чистой библиотекой.
Недавно в теме по std::visit происходили серьёзные стычки между сообществом C++ и сообществом Rust. Аргументы Rust-овщиков были вполне убедительными, поскольку Rust — это молодой язык, который создавался опираясь на горький опыт своих предшественников.
А тут такой шанс по новому взглянуть на мир в пределах плюсов, с новыми возможностями и не заменять старую библиотеку и не приклеивать новые возможности к старым с помощью скотча, а сделать всё сразу и хорошо.
Ну ведь сейчас так и происходит, что все новые фичи прикручивают к старым. Тот же constexpr почти по всей библиотеке можно прилепить. Но это ведь в корне может поменять все концепции библиотеки.
Концепты, модули и метаклассы — это через чур глобальные изменения для того, чтобы быть использованными поверх старых наработок. Необходимо использовать сей потенциал. Иначе, всё-равно все станут писать свои велосипеды. Так и происходит сейчас даже. constexpr std::swap мне приходилось писать свой, абсолютно такой же, но с constexpr. Вы продвигаете constexpr std::regex. Контейнеров новые штуки также касаются. Итераторы будут безумно изящнее с концептами. Подобных примеров уже существует уйма. Библиотека std простаивает.
Да, такой безопасности, как в Rust, не будет. Но будет гораздо лучше, чем раньше.
Но я же говорю не о безопасности, а обо всей библиотеке в целом. Да её можно сделать хоть смешав с GSL.
Факт в том, что на базе новых новшеств и базируясь на том, что язык за последние 20 лет тотально прокачался, нужно пересмотреть стандартную библиотеку вдоль и поперек. А старую оставить доживать ради обратной совместимости и всё.
Если сейчас посмотреть предложения на stdcpp.ru, то там большая часть предложений начинается со словосочетания «добавить constexpr к ...». Появляются модули, концепты и метаклассы. Это приведет к чему? К тому же самому, что происходит с constexpr. При этом модифицируя существующие сущности, которые уже много раз итак модифицировались и базировались совсем на других вещах, комитет получает головную боль, поскольку нужно все сделать аккуратно и нигде ничего не сломать и не переименовать и т.д. и т.п.
Также, что-то теряет свой смысл и со временем выбрасывается. Но это всё вытекает в то, что библиотека растянет на долгие годы (ибо стандарт выходит раз в 3 года) своё эволюционирование и в итоге придёт к тому же самому, что можно сделать здесь и сейчас и в разы проще.
Если мы сделаем std2, то как заставить пользователей на него быстро переехать? Если переезжать долго, то придётся десяток лет развивать две версии стандартной библиотеки, получать лучи ненависти от людей, вынужденных мигрировать на новую версию библиотеки…
А главное — в чём плюсы то? Пока что, всё что хочется, все новые фишки, можно добавлять к стандартной библиотеке не ломая обратную совместимость.
Если мы сделаем std2, то как заставить пользователей на него быстро переехать? Если переезжать долго, то придётся десяток лет развивать две версии стандартной библиотеки, получать лучи ненависти от людей, вынужденных мигрировать на новую версию библиотеки…
Комитет ведь что-то сподвигло сделать C++ Core Guidelines и GSL.
И я подразумеваю то, что развитие старой библиотеки прекращается. Новая в себя будет включать идентичные сущности, но без мусора, в адекватном и чистом виде.
Я не настаиваю на том, что я абсолютно прав и нужно сделать так как я говорю) Не мне решать.
А главное — в чём плюсы то? Пока что, всё что хочется, все новые фишки, можно добавлять к стандартной библиотеке не меняя обратную совместимость.
Как по мне, «пока что» — это до C++20. Уж слишком масштабное обновление будет.
Согласитесь, что constexpr уже сместил сильно с места стандартную библиотеку, о чём я выше написал.
Я вижу библиотеку сейчас, как фундамент, который не был изначально рассчитан на тот груз, который на нём стоит. И со временем любое строение изнашивается и становиться более хрупким, тем-более если сверху достроить пару этажей и дополнительные балкончики, а также кондиционеры навешать)
Так что конкретно вы хотите изменить в стандартной библиотеке? Какие основы хотите пересмотреть?
Странно записывать std::visit во что-то древнее, ему ведь всего 1 годик :)
Там весь конфликт был не вокруг std::visit, а вокруг того, что Rust-овщики пришли прогонять C++ сообщество со своими правильными умными указателями)
Жаль только что пользоваться ими не удобно, оттого и серьёзных програм на нём нет.</troll-mode>
Просто в том споре мы знатно присели, оправдывая себя «обратной совместимостью» и возрастом.
Уж слишком убедительные и настырные противники были.
Но я вот совсем не планирую уходить на Rust, поскольку душа у меня к плюсам тянется.
Также я не требую «такие плюшки как в Rust». Я сейчас о другом говорил всё время. О том, что уже есть, но под новым углом.
вот
и
вот
и я искренне надеялся на то, что так и будет с C++20.
Вы ведь и сами желайте всё то, что есть модифицировать, но с учётом обратной совместимости вам это обходиться сложнее, чем могло быть. Мне кажется, что с 20-ым стандартом всё станет еще в пять раз сложнее.
Назревает новая эпоха, а библиотека Modern C++ всё еще не Modern.
Вам не кажется, что внедрение концептов, метаклассов, контрактов, constexpr-выражений в текущую библиотеку не станет более пагубным действием и слишком размазанным по следующему десятилетию?
Суть в том, что будет абсолютно свежий код, который станет более поворотливым.
Что предлагают сейчас:
constexpr std::regex
Переименовать все новые *_ref функции и классы в *_view
algorithm который можно использовать в constexpr
std::complex который можно использовать в constexpr
Убедить международный комитет не дублировать все контейнеры стандартной библиотеки
Constexpr для std::char_traits и std::string_view
constexpr для begin/end/reverse_iterator/move_iterator и базовых методов array
std::allocate_unique
Наверняка где-то простое добавление constexpr к сигнатуре функции невозможно в связи с текущей реализацией. Далее следует цепная реакция. В итоге придётся перелопатить чуть-ли не всё, что есть. Чем это лучше?
Что вы выберете, сделать эко-жигуль, впихнув в старый эко-двигатель или сделать нормальный и современный эко-мобиль и далее уже плясать вокруг него?
Или вам нравится, когда требования к тем же контейнерам выражаются письменно где-то здесь? Это хотя-бы концептами поправят…
Говорится о новой библиотеке, которая будет эдаким ремэйком старой, но с учётом новшеств последних 10-ти лет, коих предостаточно.Для этого не нужен комитет по стандартизации. Есть пример boost. Если найдётся достаточно заинтересованных людей, которые готовы будут написать эту библиотеку — мы все только рады.
Ну а так, конечно, std::visit и std::variant по сравнению с полноценным паттерн-матчингом и алгебраическими типами данных выглядит скромненько. Только вот в обозримом времени АлгТД в C++ вряд ли завезут. Если бы завезли, то в C++ было бы проще переиспользовать полезные практики из других современных языков.
Ценность же самого C++ в том, что сохраняется совместимость с древним кодом, который написали и отладили давным-давно, но который все еще работает. У меня самого были в практике случаи, когда доставался старый код, написанный и заброшенный к тому времени уже лет 8 как, просто компилировался новым компилятором и шел в дело. Или когда старый код, который эволюционировал около 10 лет в рамках C++98 за пару вечеров был переведен под C++11. Потребовалось в ряде мест поменять std::auto_ptr на std::unique_ptr и еще что-то по мелочи. Или когда узнаешь, что где-то работает твой код, который был написан еще году в 2008-ом, и в котором были переиспользованы куски кода, написанного в 1998-ом.
ИМХО, проще тогда уже сделать новый язык, который по синтаксису, идеологии и каким-то основным приемам будет настолько сильно напоминать C++
Не соглашусь и уже далеко не одна подобная попытка была.
Стоит всё-таки разделить язык и его стандартную библиотеку.
Сам язык позволяет написать новую «идеальную» библиотеку, так что нет необходимости делать новый тысячный ЯП.
Все ключевые изменения 20-ого стандарта относятся строго к языку, а не к библиотеке, в том то и дело. И всё то, о чём я здесь так много писал, относиться только к библиотеке.
Не соглашусь и уже далеко не одна подобная попытка была.А вот я не помню ни одной заметной попытки, где хотели бы оставить синтаксис и идеологию максимально близкой к C++.
В D изначально добавляли GC, сначала его делали без шаблонов, а когда шаблоны добавили, то у них оказался совсем другой синтаксис. Хотя и при этом портировать код с C++ на D было не очень сложно, но все-таки язык с GC — это в другую нишу.
В Rust-е и синтаксис другой, и borrow-checker с lifetimes заставляют по другому думать. И объектная модель совсем другая. Так что переделать C++ный код в Rust — это даже больше, чем переписать, тут еще и перепроектировать потребуется.
Что еще?
Я имел в виду с++ контракты. Впрочем, они полностью подходят под общепринятое понятие контракта.
В данный момент у комитета нет «лучших практик» по использованию контрактов, поэтому все скользкие места помечены как UB. Разные компиляторы сделают флаги под эти скользкие места. Пользователи языка наберутся практики по использованию контрактов, и тогда станет понятно, на что именно заменить то или иное UB.
А до тех пор, комитет решил выпустить контракты в минимальном виде. Виде, который подходит для использования в стандартной библиотеке и для использования в кодовых базах ряда крупных компаний.
float twice(float x) __attribute__ ((pure))
{ return x*2.0f;}
float fourtimes(float y)
{ return twice(twice(y));}
Компилятор не узнает, что fourtimes — pure.
но гарантий нет
В контексте:
C++ компиляторы такое осилят?
Стандарт мало кого волнует. Они могут и смогут. И никаких гарантий со стороны стандарта компиляторам для этого не нужно.
Пользователям не понравится, если компиляторХ компилирует с флагами по умолчанию, а компиляторУ — вываливается с ошибкой.Как вариант, можно проверять лишь при нестандартном флаге. Как с -Werror сделано.
Поэтому для подавляющего большинства пользователей С++ это будет работать, даже если не будет обязательным, либо вообще указано стандартом. А общий случай это подавляющие большинство пользователей мало интересует. Пусть работает где-то, чем не работает везде. И это правильно.
Даже с чисто формальной ТЗ стандарта подобное поведение можно включить в «необязательно» и пусть те, кто не могут — не могут дальше.
Пользователям не понравится, если компиляторХ компилирует с флагами по умолчанию, а компиляторУ — вываливается с ошибкой.
Основная фича современных компиляторов работает именно по такой схеме. У одного компилятора может быть ворнинг у другого нет, это мало кого заботит и никаких проблем не вызывает.
Не говоря уже о самой поддержке стандартов, где код вообще может не собираться. И не собирается.
С технической точки зрения компилятор всё знает и никаких проблем нет. Если даже не хочется вводить это в стандарт — компилятор сможет за этим следить. И даже если не хочется обязывать все компиляторы делать такие «сложные» штуки, то, как я уже говорил, не обязательно включать это в обязательную часть.
остальные «компиляторы» не умеют даже с++17software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler
Остальные не проверял. Уже как минимум 4: g++, clang, microsoft, intel — немало.
для подавляющего большинства пользователей С++ это будет работатьБудет как-то работать непредсказуемым образом. Типа как статический анализ.
одного компилятора может быть ворнинг у другого нетНо не еррор. Разговор начался с «не скомпилируется с ошибкой», подразумевая гарантированное поведение, на которое можно положиться.
Не говоря уже о самой поддержке стандартов, где код вообще может не собираться. И не собирается.Если поддержка соотв. стандарта не объявлена. Если объявлена — в основном всё работает или считается багом и чинится.
С технической точки зрения компилятор всё знает и никаких проблем нет.Только в теории. Если бы всё было так просто, были бы мейнстримные языки с compile-time contract based design, а их до сих пор не существует! Даже в Rust не могут договорится о том, как их сделать и делать ли.
компилятор сможет за этим следить.В общем случае — не сможет. Как и не сможет надёжно оптимизировать код так же качественно, как тренированный человек. Максимум что можно будет сделать — это ещё один тип диагностик в статическом анализе, которые могут словить, а могут и не словить проблему.
Contract-based programming с гарантий на уровне компилятора — это не решенная на данный момент задача.
На каком основании?
Откуда вообще вы взяли свой тезис, если отвечал на:
C++ компиляторы такое осилят?
Как-то вы быстро тему поменяли. Ничего похоже на ваши тезисы я в этой ветке не видел. Зачем вы начали ссылаться на «осилят», если сейчас это для вас перестало быть существенным, и вообще играть какую-либо роль?
software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler
И? Вы увидели там c17 и вам показалось, что оно умеет в с++17? Нет, вам только показалось.
Остальные не проверял.
Остальных нет.
g++, clang
Да.
microsoft
Кое как.
intel — немало.
Нет.
И того 2.5, о которых я и говорил. Больше нет.
Будет как-то работать непредсказуемым образом. Типа как статический анализ.
И? Из этого что-то следует? Нет. Опять же, я тут вижу попытку манипулировать, ведь оно работает очень предсказуемым образом. Оно не гарантирует срабатывание на все ошибки, но на те, что срабатывает — оно срабатывает предсказуемо.
Но не еррор. Разговор начался с «не скомпилируется с ошибкой», подразумевая гарантированное поведение, на которое можно положиться.
На ворнинг можно положиться. Так же, к чему тут эта отсылка на ерррор — мне не ясно. С++ такой язык, а рантайм такая штука, что ничего предсказать нельзя и отсутствие ошибок не говорит о каком-то «положиться». Вообще нигде и никогда это ни о чём не говорит. Если вы пытаетесь апеллировать к этому, то это не тот язык, как и не любой другой в этой реальности.
Если поддержка соотв. стандарта не объявлена. Если объявлена — в основном всё работает или считается багом и чинится.
Это так смешно читать после того, как вы засыпались с поддержкой С++17 у icc.
Ваши рассуждения не соответствуют реальности, в приведенных вами компиляторах(а других нет) добавление ключика не означает 100% поддержки, а означает лишь как минимум базову поддержу. Нюансов там может быть много.
Только в теории.
В реальности, особенно в вашем примере.
Если бы всё было так просто, были бы мейнстримные языки с compile-time contract based design, а их до сих пор не существует!
Дело не в этом. Проблема знать компилятору обусловлена либо невозможность(даже в теории) что-то знать, ведь если состояние зависит от рандомного поведения рантайма, то уже никакие теории не помогут.
А вы попробуйте собрать хоть что-то так, чтобы компилятор в рамках одной единицы трансляции имел доступ к коду всей вашей программы(ведь рантайм в это понятие так же входит). В общем случае, да в и 99% реальных случаев — это невозможно. Даже лто вам не поможет в ситуации в динамически слинкованным рантаймом. Без этого даже в теории определить наличие чистоты у всех функций не представляется возможным.
Даже в Rust не могут договорится о том, как их сделать и делать ли.
Раст не показатель. Раст это не компилятор, а не уровне фронтенда там реализовано пару фишек, и то они реализованы лишь благодаря читам, т.е. введением в язык специальных ограничений. Это не является общим случае, вообще никак.
В общем случае — не сможет.
Я уже писал об этом — это мало кого интересует. Никакая собранная программа на С++ в общем случае работать корректно не может. Дальше что?
Максимум что можно будет сделать — это ещё один тип диагностик в статическом анализе, которые могут словить, а могут и не словить проблему.
И? К чему это всё. Как минимум в ситуации, когда оно может словить проблему статически — оно не будет генерировать рантайм-проверки. Это уже профит, 100% профит.
По поводу самой отсылки к каким-то гарантиям. Они никого не интересуют. Если людям это даст хоть какие-то проверки — этого будет достаточно. И всем будет абсолютно пофиг на то, что что-то там не можется. Подобные рассуждения хороши для посраться на форуме, но не более.
Как-то вы быстро тему поменялиДа нет, просто «осилят» было в контексте, который Вы проигнорировали.
вам показалосьНет, я увидел список поддерживаемых из c++17 фич, которых на данный момент 75% и динамика на увеличение с каждой версией.
Остальных нет.
EDG eccp более 80%, Intel > 75%, PGI ~50%, а что будет через 2 года?
На ворнинг можно положиться.Только если он гарантируется. Здесь же не факт, скорее будет как в статических анализаторах.
вы засыпались с поддержкой С++17 у iccЗасыпался? тем что привёл ссылку на список поддерживаемых и не поддерживаемых фич? Я не говорил, что icc поддерживает c++17, лишь указал что он движется к этому.
Дело не в этомНе в чём?
ведь если состояние зависит от рандомного поведения рантайма, то уже никакие теории не помогут.По идее в таком случае области определения — R или что там, в зависимости от типа. Вот и вся теория.
определить наличие чистоты у всех функций не представляется возможным.Я об этом говорил, что это в C++ это нереально.
Раст не показательСогласен, вы знаете примеры, где реализован compile time design by contract?
Дальше что?а то, что исходное утверждение
вам о возможном нарушении контракта скажет компилятор еще на этапе сборки.не совсем корректно т.к. пропущено «если повезёт».
По поводу самой отсылки к каким-то гарантиям. Они никого не интересуют.Ну как, исследования то идут.
Если поддержка соотв. стандарта не объявлена. Если объявлена — в основном всё работает или считается багом и чинится.
EDG eccp более 80%, Intel > 75%, PGI ~50%
Дак работает, либо на 50%?
У вас вилка, если вы признаете, что «в основном работает» — это 50%+, то ваши рассуждения на тему «должно собираться» — не работают, ведь оно попросту не будет собираться.
Это является попыткой опровержения моего тезиса:
Не говоря уже о самой поддержке стандартов, где код вообще может не собираться. И не собирается.
Т.е. вы предполагаете, что «заявленная поддержка стандарта» должна позволять компилятору собирать стандартный код и не иметь описанного мною поведения.
Ваши два ответа мне противоречат, по крайней мере, друг другу. Разрешите противоречие.
Дак работает, либо на 50%?Если объявлена, то работает. Что объявлено, то и работает.
Заявленная поддержка стандарта должна позволять компилятору собирать то, что заявлено. На данный момент 2.5 компилятора заявили практически полную поддержку, и еще 2-3 двигаются в этом направлении, два из которых довольно близки к достижению полноценной поддержки, как мне кажется.
Если объявлена, то работает.
Она не работает, значит не объявлена(на самом деле объявлена(Use compiler option -std=c++17), но это будет слишком просто), значит не поддерживает, значит не собирается.
Таким образом ваша попытка оспорить:
Не говоря уже о самой поддержке стандартов, где код вообще может не собираться. И не собирается.
Целиком и полностью несостоятельна.
Точно так же, как и:
остальные «компиляторы» не умеют даже с++17
software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler
Остальные не проверял. Уже как минимум 4: g++, clang, microsoft, intel — немало.
Таким образом, вы пытались выдавать тех, кто не умеет:
два из которых довольно близки к достижению полноценной поддержки
Близки не значат могут. За тех, кто умеет. Это нехорошо.
Таким образом, как я и говорил, умеют в с++17 только 2.5 компилятора.
Целиком и полностью несостоятельнаНу почему же. Поддержка может быть частичной.
остальные «компиляторы» не умеют даже с++17Умеют частично, как минимум 2 на более чем 70% фич. Умеют почти полностью 2, и один — с натяжкой. В той или иной мере — не менее 5.
Ну почему же. Поддержка может быть частичной.
Абсолютно неважно, она несостоятельна в любом случае, если этот случай не «полная поддержка». Напомню, что вы оспаривали возможно собираться/не собираться на разных компиляторах стандартного кода. С частичной поддержкой — он так и будет, то собираться, то не собираться и никакой «уверенности» у вас не будет.
Умеют частично, как минимум 2 на более чем 70% фич.
Инфу вы скорее всего взяли отсюда:
en.cppreference.com/w/cpp/compiler_support
Смотрим на поддержу с++14 у icc — даже она не полная. Я проверил constexpr у complex — его нет, т.е. NA == не работает.
Смотрим на поддержу С++17 — она никакая. Нету там 70%. От силы 50%
Что такое «EDG eccp» мне неведомо. Гугл находит только какой-то фронтед, т.е. это вообще не компилятор, либо гугл о нём не знает.
И того, 2.5 компилятора(можно даже msvc записать третьим, если поверить в честность МС. Но он вендорлочный, а так же слаб как компилятор) + какие-то куски поддержки у icc. Всё, больше мир компиляторов не знает.
icc я считал по таблице с сайта интел, там 9 из 37 пунктов указаны без поддержки — ~75% поддерживается.
Ну они как минимум могут написать не все пункты из стандарта(что мы и видим) + разные пункты не равнозначны.
en.cppreference.com/w/cpp/compiler_support — вот тут есть и оракловский и айбиэмовский и хпешный. Результаты нулевые.
Хоть icc и стал как-то догонять стандарт, а не то, что было раньше. Но всё же — чуда не произошло. Компилятор этот достаточно специфический и мало претендует на звание передового.
Вот и остаются gcc/clang из портабельных + один вендорлочный, который недавно так же начал догонять. Посмотрим, на сколько его хватит.
Не в чём?
Это очевидно и был дан конкретный пример, компилятор ограничивает уже давно не сам компилятор, а подходы к использованию этого компилятора, т.е. к компиляции кода.
Я об этом говорил, что это в C++ это нереально.
Очередной дёрганье фразы из контекста с «я же говорил», нет. Вам сообщили о том, в описанной мною ситуации что-то является невозможным, но эта проблема только конкретной ситуации, которую легко обойти. И если она у вас есть — это чисто ваша проблема. Она не определяет невозможность.
Согласен, вы знаете примеры, где реализован compile time design by contract?
Зачем вы пытаетесь пропихнуть новые, свободно-трактуемые, термины в обсуждение? Это настолько глупо.
Любая реализация чего-либо сравнивается с идеалом, причём этот идеал определяется не вашими фантазиями на тему. У нас есть какой-то код, есть некий порог, объективный порог — то, даже чего не может пойти статический анализ. За него зайти нельзя.
И нет смысла рассуждать о том, что находится за этим порогом. Это просто демагогия и попытка отмыть свои суждения. Если конкретней, то нет смысла рассуждать о том, чем в принципе существовать не может. Не может существовать 100% полного как compile time design by contract, так и рантайм. Всегда будут какие-то допущения, да в части кода исполняющего в рантайме ратайм проверки более мощные, но они имеют и свои минусы, которые на поверхности.
В какой-то мере design by contract существует в компиляторах и сейчас, только он не прямой и эти контракты описываются косвенно. Ссылаться же на другие языки не имеет смысла, С/С++ имеет самые передовой компилятор в сравнение с которыми все остальные — детский садик.
не совсем корректно т.к. пропущено «если повезёт».
Во-первых я говорил не об этом, а вторых оно корректно. Ваши «если повезёт» — глупости. Всё в этом мире работает в ситуации «если повезёт». Но дело не в этом.
Давайте подумаем:
о возможном нарушении контракта
Это можно трактовать как допущение ложно-положительных срабатываний, в ситуации когда компилятор не может ничего проверить. Т.е. он будет говорить «я не знаю — возможно нарушение — вставлю проверку/сообщу пользователю». Если же он что-то нашел, то результаты уже объективны и он точно сможет сказать — есть ли там нарушение, либо его нет.
Таким образом ситуации в которой контракт будет нарушен, но компилятор об этом не скажет — быть не может, может быть ситуация «нарушений нет, а показывает, что „возможно есть“», но это не проблема.
Ну как, исследования то идут.
Они могут идти сколь угодно долго, но это ничего не даст. Это невозможно. В общем случае поведение рантайма в компилтайме предсказать невозможно, точка.
Есть два варианта: это изучать и основывать свой анализ на поведение конкретного окружения, но это не будет «в общем случае». Либо, создавать искусственное окружение с какими-то заранее определёнными свойствами, либо другой путь того же — отсекать возможность у программы делать то, результат чего может быть непредсказуем.
Но всё это сужение общего случая.
Ветку обсуждения поддержи стандартов со стороны компиляторов постигла неудача( с вашей стороны),Вы завели диспут по поводу второстепенного по отношению к обсуждаемой теме технического нюанса, с которым я и не спорил, и сами у себя его выиграли. Ну ОК.
С чем вы спорите? С каким утвержденим? Напомню, мой основной тезис:
В C++ нельзя положиться на то, что нарушения контрактов (как они есть в текущем proposal) будут обнаружены на этапе компиляции, как писал изначально Antervis. Есть некоторое число несложных частных случаев, когда это сработает, но в основном — нет. Это и понятно, ведь, если я правильно понял, contracts proposal — это немногим более чем новый синтаксис для assert. Если Вы с этим тезисом согласны, то о чем спорите?
В общем случае поведение рантайма в компилтайме предсказать невозможно, точка.Для меня не очевидно, почему в рамках конкретного (возможно, пока не созданного) языка программирования это невозможно, возможно с исключениями типа unsafe в Rust, но всё же. Есть же seL4 и Spec#.
Что до многопоточного случая — формально, data race без примитивов синхронизации — ub. А при наличии примитивов синхронизации уже известно, где теряются гарантии контракта.
По сути, в коде без ub контракты будут работать на уровне поддержки их компилятором.
В однопоточном случае обнаружить нарушение контракта компилятор скорее всего сможетНе верится в «скорее всего». Для этого фактически компилятор должен свести условие контракта до constexpr!, что в C++ чаще невозможно, чем возможно.
По сути, в коде без ub контракты будут работать на уровне поддержки их компилятором.Что Вы имеете ввиду? Согласно пропозала полная поддержка компилятора означает просто поддержку проверки в runtime (как assert), если я правильно понял.
Кроме того, как компилятор будет отличать многопоточный случай от однопоточного?
Для этого фактически компилятор должен свести условие контракта до constexpr!, что в C++ чаще невозможно, чем возможно.
Компилятор может оптимизировать и то, что не constexpr, так ведь? Только гарантий нет. Вот здесь то же самое.
Что Вы имеете ввиду? Согласно пропозала полная поддержка компилятора означает просто поддержку проверки в runtime (как assert), если я правильно понял.
Компилятор может реализовать определенный набор оптимизаций на базе информации из контрактов, но сейчас не обязан. В дальнейшем контракты будут дорабатываться и облагаться доп. гарантиями.
Кроме того, как компилятор будет отличать многопоточный случай от однопоточного?
отслеживать входы/выходы из критических секций.
Компилятор может оптимизировать и то, что не constexpr, так ведь?Так. То есть вероятность, что нетривиальный контракт будет проверен на этапе компиляции примерно такая же, как и вероятность того, что аналогичное выражение было бы оптимизировано компилятором до `noop`. Невысокая, как мне кажется. Ну и, что хуже всего — это то, что программисту будет очень трудно уверенно предсказать, когда это сработает, а когда нет. Для оптимизаций это нестрашно, а для контрактов — весьма неприятно.
он попросту предупредит «вот здесь может быть нарушен контракт».Если он будет предупреждать об этом в 9 контрактах из 10, то толку? С лишней проверкой будет работать только в дебаг билде.
В самом худшем случае мы получим то же самое число лишних проверок пред/постусловий, что и в коде до контрактовНу да, точно как с assert.
Вы завели диспут по поводу второстепенного по отношению к обсуждаемой теме технического нюанса, с которым я и не спорил, и сами у себя его выиграли. Ну ОК.
Таких нюансов было много, просто они очень показательны. Они говорят о серьёзности аргументальной базы.
В C++ нельзя положиться на то, что нарушения контрактов (как они есть в текущем proposal) будут обнаружены на этапе компиляции,
Контракты не являются контрактами времени компиляции. А то, что будет работать на этапе компиляции — на это можно положиться.
Опять же, ложно-положительную(в контексте нарушения) ошибку компилятор дать не может, а значит всё валидно и я на это уже отвечал.
Вы тут начали вилять «а как так компилятор может собирать/не собирать код по своей воле» — вам ответили «так же, как он это делает сейчас», на что вы начали вилять в сторону «не делает, если он поддерживает(заявляет об этом) стандарт — он не может не собрать код). На что я вам ответил и доказал, что может и делает.
Это и понятно, ведь, если я правильно понял, contracts proposal — это немногим более чем новый синтаксис для assert.
Нет, вы ещё утверждали то, что „они ничего не отличаются от асертов“/»преимуществ не имеют", а как мы выяснили — имеют.
Но вы продолжаете игнорировать свои начальные тезисы и ссылать на то, что придумали после.
Для меня не очевидно, почему в рамках конкретного (возможно, пока не созданного) языка программирования это невозможно, возможно с исключениями типа unsafe в Rust,
«За исключениями» — противоречит общему случаю. У общего случая нет исключений, на то он и общий. Вам это тоже не очевидно?
Есть же seL4 и Spec#.
Это всё типичная подмена понятий и манипуляции. Никакого отношения они к гарантиям не имеют и никакое поведение рантайма не предсказывают.
Они просто живут в песочницах, которые им организовывают те самые песочницы на языка, которые ничего не гарантируют и не предсказываю, а предсказывают конкретные люди и для конкретных случаях. За рамках этих случаев — песочницы не работают.
Это не контекст нашего разговораА что же это? Это то сообщение, на которое я отвечал. Как это может не быть контекстом? Вы продолжаете этот контекст игнорировать.
Вы так и не показали определяющих контекст ваших заглавных постовМногократно показывал. Повторяю последний раз.
Вот комментарий, на который я отвечал:
вам о возможном нарушении контракта скажет компилятор еще на этапе сборки.И мы с автором уже разобрались в вопросе. Что Вы цепляетесь к каким-то вырванным из контекста репликам?
это ваши попытки отмыть себяЧто Вас так заботят мои внутренние мотивации? Кругом враги? Оставляю вопрос об истоках хамства, глупостей и демагогии в Ваших постах Вам на самостоятельную проработку.
Многократно показывал. Повторяю последний раз.
Вот комментарий, на который я отвечал:
Меня мало интересует то, на что вы где-то отвечали. Мне нужны конкретные ваши утверждения, и они у меня есть и я их вам показывал. И в каждом из них вас постигла неудача.
Контекст определяют ваши ответы, которые были до моих. ВАШИ, а не чьи-то. Ссылать на левый пост задним числом трактовать его хочется — это не контекст.
И мы с автором уже разобрались в вопросе. Что Вы цепляетесь к каким-то вырванным из контекста репликам?
Я не цепляюсь, я цепляюсь к конкретным вашим неудачам. Я отвечаю за свои тезисы и отвечаю на ваши. Ссылки на левые комменты, которые вы пытаетесь задним числом трактовать как удобно — не работаюют.
Что Вас так заботят мои внутренние мотивации?
Да, юлить можно сколько угодно. Это бесконечный процесс. Врать, игнорировать свои, либо оппонента тезисы — это ваша основная методика. И решение очень простое, я ловлю трепача на его удачах, а после уже что-то мало волнует.
Неудачи есть — пациент врёт. А раз он врёт, то ни о какой объективности и вменяемости в споре с ним речи быть не может.
Оставляю вопрос об истоках хамства
Покажите хамство? Я думаю точно так же, как вы мне показали четвёртый поддерживающий С++17 компилятор.
глупостей и демагогии в Ваших постах Вам на самостоятельную проработку.
И где же они? Где глупости, почему вы не отвечаете и не показываете их? Тоже самое вы говорили и о компиляторах, но оказалось, что вы просто болтали. И у меня есть прецедент на который я могу постоянно ссылаться, а значит — все ваши попытки придумывать новые оправдания — тщетны.
Меня мало интересует то, на что вы где-то отвечали.Я и говорю, Вы сами с собой спорите и вырываете мои слова из контекста, который задаётся всеми предыдущими репликами в диалоге, не только моими. Как крайний пример «согласен» вообще без предшествующей реплики не имеет смысла.
Ссылки на левые комменты, которые вы пытаетесь задним числом трактоватьЗадним числом? Я не менял позицию по поводу той реплики и даже уже коротко излагал её повторно. Все мои реплики станут Вам понятны, если вы прочитаете диалог не с середины, а с начала.
Да, юлить можно сколько угодноАппелировать к личности тоже, но мне это не интересно. По сути Вам сказать, видимо нечего.
я ловлюНикого Вы не ловите, только демагогию разводите, вырывая из контекста и не понимая, что прочитали.
пациент врётКругом враги и дураки?
вы мне показали четвёртый поддерживающий С++17 компилятор.Ну снова вы за меня додумываете и демагогию разводите. Так-то и одного поддерживающего С++17 компилятора не существует, у всех есть хотя бы небольшое несоответствие. Там в контексте было понятно, что речь шла о, возможно, частичной поддержке.
почему вы не отвечаете и не показываете ихПотому что это мне не интересно, меня Ваша личность не интересует, мне не нужно самоутверждаться, пытаясь кого-то поймать на чем-то.
у меня есть прецедент на который я могу постоянно ссылатьсяВо первых, Вы можете ссылаться только на свою демагогию и придирки не по теме. Во-вторых даже если бы я ошибся, это ничего не доказывает.
Ну снова вы за меня додумываете и демагогию разводите.
остальные «компиляторы» не умеют даже с++17
software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler
Остальные не проверял. Уже как минимум 4: g++, clang, microsoft, intel — немало.
Т.е. тут человек отрицал моё утверждение, в противном случае он бы это не писал. Это явное отрицание:
С чего же всё началось:
Нужно, если компилятор будет выдавать ошибку компиляции. Пользователям не понравится, если компиляторХ компилирует с флагами по умолчанию, а компиляторУ — вываливается с ошибкой.
Т.е. человек утверждал, что пользователям не нравится, когда один собирает, а другой нет. Всё это было в контексте того, когда я говорил «на сломанный контракт компилятор может давать ошибку(на самом деле я этого не говорил и это очередное вранье, но я пойду человеку навстречу)».
Это человек пытался крыть тем, что вы видите выше. Т.е. отсылкой на то, что это плохо.
На что я ответил тем, что вы так же видите выше. Компиляторы итак не собирают один и тот же код ДАЖЕ С ЛЕВЫМИ ФЛАГАМИ, не говоря уже о «по умолчанию».
И того мы видим тут явную ошибку. Ошибка и по части утверждений в сторону поддержки стандарта у более, чем 2.5 компиляторов. И в части попытки съехать на «компиляторы не могут компилировать/не компилировать код по своему желанию», которая так же оказалась неудачной. Могут, при это ещё как.
Я уже один раз позволил человеку уйти от ответа, но похоже он ничего не понял и продолжает врать. На этот раз такого не будет.
И тут существует два варианта, первый — человек объясняет почему и как так вышло, и почему неправ я, а не он. Второй — я могу с чистой совестью признать оппонента вруном и болтуном, которые не мотивирован к честному диалогу, а мотивирован врать и оправдывать собственные неудачи/ошибки.
Эти машины реализуются на языка, для которых «предсказать поведение в рантайме» невозможно. Авторы этих машин идут другим путём, они берут некий конкретный исполнитель, не кую архитектуру, поведение которой достаточно предсказуемо. Это и позволяет им получить предсказуемое поведение.
Но позволяет получить его только в одном случае, в общем случае его получить невозможно. Тут уже можно закончить, но продолжим. Авторы этой машины обобщают обобщаемое для некого набора архитектур, реализуя отдельно для каждой то, что не обобщается.
Таким образом получается реализовать то, что работает не в одних, а в нескольких условиях. В любом случае — это не является общим случаем.
Далее, те языки, которые работают в рамках этой машины — очень ограничены. Их возможности заканчиваются за рамками этой машины, они не позволяют хоть как-то коммуницировать с реальным миром. Для этого им нужны прокладки. Они не являются так же «языками общего случая».
Таким образом, упомянутый вами языки не являются предсказуемыми. Они существует в рамках непредсказуемой ВМ, непредсказуемых биндингов, ограниченных возможностей. Каждый из этих пунктов целиком и полностью противоречит понятию «общий случай».
Даже если говорить о языках, о всякой хардкорщине вроде языков с зависимыми типами, некоторые из них вполне себе могут взаимодействовать с внешним миром.
Не могут, по определению. Но вы можете легко это опровергнуть без всяких пустых рассуждений для этого достаточно показать лишь одно — язык без вм.
Естественно, есть некоторые предположения о нижележащей реализации.
Дело не в этом, каждая реализация обладает своими свойства и завязка на конкретные реализации работает только в рамках этих конкретных реализаций. Всё, точка. Учитывать нюансы работы каждой конкретной платформы в общем случае невозможно.
Ни о каких микродах и космических лучах речи не шло — это было бы слишком просто, для меня.
Всё в этом мире работает в ситуации «если повезёт».Это демагогия. В контексте нашего разговора примером гарантированного поведение (в противоположность «если повезёт») являются гарантии, которые обеспечивает Rust или Haskell, например. В C++, contacts proposal не предполагает вообще никаких дополнительных гарантий, кроме тех, что есть у assert. Я предполагаю, что эта ситуация, к сожалению, фундаментально не улучшится из-за особенностей C++: его системы типов, и устройства C++ компиляторов которое продиктовано самим языком.
искусственное окружение с какими-то заранее определёнными свойствамиСтандарт языка программирования и есть этим искусственным окружением. C++ не достаточно сужает контекст что бы реализовать сколь-нибудь серьезный static contact-based programming, как мне кажется.
В контексте нашего разговора примером гарантированного поведение (в противоположность «если повезёт»)
Это не контекст нашего разговора — это ваши попытки отмыть себя. Вы так и не показали определяющих контекст ваших заглавных постов(не тех, которые были после, а те, которые были в этой ветке на момент моего ответа).
которые обеспечивает Rust или Haskell
Ничего они не обеспечивают «в общем случае» и я уже об этом говорил. Но будучи вами очень удобно спорить — можно просто брать и игнорировать неудобные тезисы/ответы.
Всё это работает в рамках неприемлемых для С++ рамках, в которых существует раст/хаскель. Что тут делает хаскель — мне неясно. Но у раста даже формально есть ответ — unsafe и всё, всё очень быстро и сразу перестаёт работать.
В C++, contacts proposal не предполагает вообще никаких дополнительных гарантий, кроме тех, что есть у assert.
«Не предлагает» не значит, что их не может быть. proposal не запрещает компилятору в каких-то случаях их выпиливать на базе своих, внутренних, обоснований.
Вам на это указали, вы теперь пытаетесь ехать в сторону «а гарантий то нет» — только об этом я не говорил, да и вы тоже.
Стандарт языка программирования и есть этим искусственным окружением.
Не в случае С++.
C++ не достаточно сужает контекст что бы реализовать сколь-нибудь серьезный static contact-based programming, как мне кажется.
Оно и не нужно. Нужно лишь лучше ассертов, а всё остальное — ваши придумки.
Только в том случае, если вам условные данные приходят по сети или из файла, и статически что-то про них гарантировать вы не можете при всём желании. Тогда да, конечно. Но от этих проверок вы и так никуда не убежите.
Я не об этом говорил. Я говорил о том, что если какую-то часть рантайм-проверок можно свести к компилтайму, то нужно это делать и это профитно.
А все рассуждения уровня «ну не все же можно» — простая демагогия, когда нету ответов.
По части оптимизации — да. По части системы типов — ну…
Это простая ссылка на то, чего в С++ нет, но это не значит, что это является чем-то более сложным, чем то, что есть сейчас в С++.
Система типов не такая, но заморочек так не мало, и её реализации требует не меньшего кол-ва логики, нежели любой другая, которая «ну...».
Вы ещё говорили о том, что рантайм-проверки более мощные.
Естественно, что в рамках рантайма рантайм-проверки более мощные.
Либо у нас с вами сильно разное определение мощности, либо это совсем не так.
В чём конкретно проблема?
Только в том случае, если вам условные данные приходят по сети или из файла, и статически что-то про них гарантировать вы не можете при всём желании. Тогда да, конечно. Но от этих проверок вы и так никуда не убежите.
В контексте кодогенерации. Прокомментирую это более подробно. В случае с данными «по сети»/«из файла» я уйду от проверок статически. Не ото всех, но уйду. Статически я могу имплементировать оптимальные проверки. Таким образом, даже если некая валидация данных происходит в рантайме — чистые компилтайм-проверки проигрывают миксу.
Решённая. Просто не в С++.А где? Самое продвинутое, что мне известно — это Eiffel и Spec# и не то что бы там прям вот всё гладко. Как я понял, авторы решили, что для внедрения в мейнстрим не готово. Тянуть доказательства вручную через весь код — это, как мне кажется не достаточно хорошее решение. Слишком много геморроя, нужна автоматизация.
механизм для уменьшения числа проверок в рантаймеИ чем же контракты в этом плане выигрывают у std::assert? Что такого в них есть, что позволит снизить число проверок в рантайме, по сравнению с использованием assert?
вы будете знать о том, что библиотечная функция не умеет принимать nullptr на этапе компиляцииНет, придётся смотреть документацию всё равно. Узнать о том, что библиотечная функция не умеет nullptr можно будет только намеренно подав в неё nullptr и запустив эту ветку кода, дождаться исключения.
чем ensures отличается от assert перед return? С точки зрения компилятора?
а если компилятор не знает о том assert'е?
Нет, придётся смотреть документацию всё равно. Узнать о том, что библиотечная функция не умеет nullptr можно будет только намеренно подав в неё nullptr и запустив эту ветку кода, дождаться исключения.
Если у функции объявлен контракт, компилятор даже не соберет код с ошибкой «вы собираетесь передать nullptr в функцию, которая его не ждет» или «здесь возможен nullptr, а вот эта функция его не умеет, добавьте проверку»
а если компилятор не знает о том assert'е?Согласен, в случае бинарной библиотеки контракт — это удобный способ сохранить assert <в header файле>.
не соберет код с ошибкой «вы собираетесь передать nullptr в функцию, которая его не ждет»
int value(int* ptr)
[[expects: ptr != nullptr; ]]
{return *ptr;}
int main()
{
int a=1;
int* p=&a;
//in parallel thread: p=nullptr;
return value(p);
}
Компилятор не знает на этапе компиляции, что такое p.
«здесь возможен nullptr, а вот эта функция его не умеет, добавьте проверку»Врядли компилятор такое сможет в общем случае. Вывести всё множество возможных значений параметра в c++ звучит фантастически. Нет даже механизма указать, что p — !nullptr, можно только надеяться, что компилятор откуда-то сам это выведет. Но нет никаких гарантий, что там, где один компилятор выведет — другой тоже осилит, этого нет в стандарте.
Что до многопоточного — наверно, как всегда надо аккуратно проектировать и использовать потокобезопасные инструменты. А ошибки ловить контрактами в отладочном режиме. Даже в вашем примере, в силу отсутствия volatile, после оптимизаций в value(p) может передаться &a.
Ошибка компиляции должна гарантироваться (стандартом) на всех компиляторах
Не обязательно. Стандарт описывает базовый механизм описания контрактов, а конечному компилятору ничего не мешает выдавать ошибки/предупреждения без оглядки на стандарт, что он и делает во многих других случаях.
Поэтому, в контексте «а могут ли больше, чем ассерты?» — могут. И стандарту для этого гарантировать ничего не нужно. А в ситуации с асертами — этим никто заморачиваться не будет, и там даже «могут» не сработает.
Стандарт описывает базовый механизм описания контрактовНо не требования к проверке их выполнения, кроме тех что определены для assert. Поэтому я и говорю, что на данный момент контракты — это скорее способ документирования.
Какие есть случаи, когда со стандартными флагами компиляторы выдают разные ошибки компиляции и это воспринимается как должное?
Но не требования к проверке их выполнения, кроме тех что определены для assert.
Нету, но разговор был не об этом. Вы просили назвать преимущества — вам их назвали. Ссылки на «а вот в стандарте нет» тут мало применимы, ворнингов и прочего статического анализа в стандарте тоже нет, но это же не значит, что его нет.
Так и тут. Есть механизм, который позволяет реализовать этот анализ намного проще и понятней. И естественно, что он лучше, нежели рандомные ассерты. И шансы на то, что компиляторы реализуют какие-то проверки для них — несоизмеримо выше, нежели в ситуации с асертами.
Преимущество очевидно.
Какие есть случаи, когда со стандартными флагами компиляторы выдают разные ошибки компиляции и это воспринимается как должное?
Ну дак это ничему не мешает, в стандартном режиме можно и подавлять ошибки. В любом случае ворнинги никому не помешают, а уже этого достаточно. А Werror — есть всегда.
Вы просили назвать преимущества — вам их назвалиНе совсем, я отвечал на «не соберет код с ошибкой» и говорил, что в общем случае компилятор не сможет выдать ошибку. А в остальном я согласен — такой себе assert-based static analysis.
И чем же контракты в этом плане выигрывают у std::assert? Что такого в них есть, что позволит снизить число проверок в рантайме, по сравнению с использованием assert?
Вот заглавие ветки. Очевидно, что я на это ответил. Упрощение реализации статических проверок уже является преимуществом над ассертами, и так же позволяет сократить вычисления в рантайме.
Нет смысла гонятся за мистическим «общим случаем», которого нигде в реальности нет. У нас есть простой выбор — иметь хоть что-то, либо не иметь ничего. А сидеть без ничего обвиняя тех, кто предложил хоть что-то в том, что их предложение «работает не всегда» — пустая затея.
Вот заглавие ветки.Но это ещё не весь контекст.
Нет смысла гонятся за мистическим «общим случаем», которого нигде в реальности нет.А с этим никто и не спорил. Человек написал «вы будете знать о том, что библиотечная функция не умеет принимать nullptr на этапе компиляции» и «не соберет код с ошибкой», а я добавил "… если повезёт". Всё.
Но это ещё не весь контекст.
Нет, весь. Я не видел и не вижу ничего, что добавляло деталей в этот контекст. Может я плохо искал?
Человек написал «вы будете знать о том, что библиотечная функция не умеет принимать nullptr на этапе компиляции» и «не соберет код с ошибкой», а я добавил "… если повезёт". Всё.
Это уже контекст другого человека, а не ваш. К тому же, это целиком и полностью противоречит вашим начальным утверждениям. Не всегда всегда больше никогда, а вы утверждали «никогда»(либо, по крайней мере, «меньше, чем не всегда»).
Моё утверждение в том, что «вы будете знать о том, что библиотечная функция не умеет принимать nullptr на этапе компиляции лишь иногда/если повезёт». Где я писал иначе?
То что я писал, я писал в ответ на все это обсуждение.
Так не бывает, вам показали противоречия в ваших суждениях, когда вы вопрошали о «а что же может быть в сравнении с ассератами» — вам показали, вы начали ехать в сторону «а ну дак это же не гарантирует». Там вы много где засыпались, начиная с того, что само требование гарантий времени компиляции в контексте С++, да и вообще какого-либо реального язык — целиком и полностью несостоятельны.
Вы не просили о гарантиях, никаких гарантий нет и быть не может, но вы продолжаете всё игнорировать и придумать всё новые и новые обстоятельства.
Моё утверждение в том, что
Дайте ссылку на конкретный комментарий с вашим утверждением, который существовал до нашего диалога.
Ассерты выкидываются на этапе препроцессинга. Поэтому компилятор ничего не знает о том что они там были. Контракты выкидываются самим компилятором. Компилятор выкинет проверку на, например, ненулевой указатель, но все равно сможет использовать "сакральное знание" для оптимизации.
float sqrt(float x)
{
if constexpr(stateof(x, float#nonnegative) {
return ::sqrt(x);
}
return NaN;
}
int a=123; //int
int b=(i+5)*2; // int#even
int c=b*b; //int#even#nonnegative
float d=sqrt(c); //call sqrt(float#notNaN#nonnegative)
где «теги» (state) типа (#even, #nonnegative, etc) определяются на этапе компиляции. И в функции они передаются тоже, в идеале прозрачно для пользователя.
Ну или оставить всё как есть, а продакшн переводить на какой-нибудь другой язык (rust?). Как мне видится — с++ превратился в поле для экспериментов: много удобных фич там появляется, а потом часть медленно кочует в другие, более простые языки.
2. Для новых проектов не вижу проблемы использовать только свежее подмножество С++
3. Продакшен с С++ на Rust никто так просто не возьмётся переписывать, потому что на это не так просто выбить денег. Да и есть ли смысл?
4. Хм… а мне вот кажется, что наоборот в С++ тянут вещи из других ЯП. В С++ же всё обсасывается годами (что неплохо, имхо)
Получится Core C++ Guidelines.
Считаю, что поддержку многопоточности, файловой системы и сети надо было добавлять самыми первыми до синтаксических улучшений.
Да, и смешно: получается обработка одного файла (указанного в настройках программы или интерактивно пользователем), в один поток (при этом с зависанием интерфейса) и с отображением результата выполнения программы только на этом компьютере (нельзя отправить результаты по сети или сообщить о завершении работы). Попахивает 80- ыми годами :)
С++ только Qt спасает, иначе бы умер язык как не соответствующий текущим реалиям.
Может вместо коробки попросите нормальный менеджер пакетов?
Вот есть у вас контейнеры из коробки, с одной стороны выше вон просят прекратить насиловать труп std и заменить на std2, с другой не смотря на искоробочность, куча библиотек реализуют свой строковый тип.
… куча библиотек реализуют свой строковый тип.
проблема не в том, что у всех свой строковый тип а в том, что он у всех разный. Сравните std::string, bstr_t и QString — они отличаются буквально всем. Увы, но так просто всем не угодишь.
Зачем эти лишние телодвижения?
А как же QRunnable + QThreadPool, которые позволяют работать на более высоком уровне задач, а не функций (как в классическом С++). Я еще там юзаю события, QReadWriteLock и файловую систему (которую пока компиляторы не реализовали).
Ну и вот, если у нас такая задача, что нам хватает тредпулла, то каким образом оно стало менее качественным? Оно наоборот стало более качественным, ведь чем меньше всяких заморочек, тем меньше шансов ошибиться. И тут это слово не играет новыми красками.
Я где-то видел ваши(либо не ваши, но с со) баталии на тему многопоточности, когда решение на том же thread pool было проще и удобнее.Возможно, речь про «обедающих философах», которые обсуждались на LOR-е.
Ну и вот, если у нас такая задача, что нам хватает тредпулла, то каким образом оно стало менее качественным?Если под «качеством» понимать реализацию конкретно тред-пула в разных библиотеках, то может ваша точка зрения оправдана. Если под качеством понимать удобство решения задач из области parallel или concurrent computing, то более специализированный инструмент мне представляется более качественным.
Но тут, полагаю, идет спор о том, кто и как воспринял слова DaylightIsBurning, а не о том, что именно он подразумевал. Так что лучше дождаться его объяснения.
за каким… извиняюсь, вам тянуть специализированную библиотекуПринцип единственной ответственности. В этом вся суть программирования — брать наиболее удачные/подходящие реализации необходимых компонент (библиотеки) и комбинировать их. Задача авторов библиотек — сделать так, что бы они могли хорошо интегрироваться со сторонними библиотеками. Задача языка — предоставить для этого возможность. Разработка своих собственных уникальных и неповторимых решений для уже решенных задач — это недостаток, а не преимущество для фреймворка. Ну не могут Trolltech объять необъятное и предоставить лучшее модульное решение для всех направлений, которые Qt пытается закрыть. Раньше это было оправдано, когда альтернатив не было. Сейчас же QVector — это ненужный велосипед, который вынуждает только лишний раз морочить голову с передачей QVectror<->std::vector. Если решение от Qt не может конкурировать с альтернативами за пределами Qt приложений — скорее всего оно не нужно.
А «тянуть ещё одну библиотеку» — это вообще не проблема, если библиотека нормально организована. Тут, конечно, было бы круто иметь модули и пакетный менеджер, как в других языках типа Python или Rust.
Почему это QVector ненужный велосипед, а не std::vector? В QVector, к примеру, можно настроить копирование POD элементов через системный intrinsic, а в std::vector это делается только через стандартные конструкторы копирования. И морочить голову с передачей std::vector туда-обратно не нужно, все методы уже есть в QVector, с самого его появления. Кроме того, в отличие от std::vector, QVector это не header-only класс, а значит его использование не приводит к «распуханию» результирующего кода, что актуально в больших проектах (потому как контейнеры — это базовые «кирпичики» и применяются на всех уровнях).
Trolltech уже много лет никакого отношения к Qt не имеет, значит и о Qt вы знаете только понаслышке.Да я в курсе, что они название поменяли, но люди остались те же. Ларс Кнолл, который сейчас CTO пришел ещё в Trolltech. Так что не спешите с выводами.
А то что на практике не выходит всегда всё «по науке» это понятно, но это не повод теперь намеренно проектировать через ж.
в C++ у вас не получится «по науке»Тем не менее развития языка и библиотек представляет возможность сделать более «по науке». Qt от этого развития, на мой взгляд, по некоторым параметрам отстаёт из-за того, что продолжает тянуть «ненужные» куски. Я согласен с Вашим посылом, просто, мне кажется, за время развития Qt оптимум между «правильностью» и «практичностью» сильно сдвинулся в пользу «правильности», а Qt не везде за ним поспевает.
Это значит, что если ваша библиотека не использует, к примеру исключения, то объединить ее с другой, использующей их, будет почти невозможно и обязательно это будет получаться только через жо… это самое
почитайте про паттерн «адаптер»
Почему это QVector ненужный велосипед, а не std::vector?
как минимум потому, что у QVector'а v[i] = 0; может выполняться линейное время. Он был хорош до с++11, но не после введения move-семантики
Это бы хоть-как то помогло с интеграцией ее с другой сторонней библиотекой, также использующей стандартную библиотеку C++?Да, библиотека стала бы меньше при этом нужная функциональность всё равно есть в std и ко. Интерфейсы с другим кодом упрощаются, не нужно вечно на каждый std::string городить QString::fromStdString() и т.п. К тому же работа c Qt для программистов упростилась бы — не нужно вникать в особенности Qt-шных альтернатив. Одно только засилье сырых указателей и сопутствующих приблуд чего стоит.
А как же разворачивание шаблонов? STL генерирует много дублирующего кода.
…
Но да, в некоторых случаях в STL меньше накладных расходов чем в Qt, хотя упрощение процесса разработки сильно перевешивает, по крайней мере, для меня
Во-первых, невозможно STL-ем надублировать больше шаблонного кода, чем весит даже базовый комплект Qt. Во-вторых, Qt генерирует много шаблонного кода для метаобъектной информации.
В-третьих, накладные расходы Qt'а вам в радость, а STL «код раздувает». Как будто QVector/etc. не генерируют шаблонный код…
Там где строку надо копировать для изменения, это очень не факт что вы не забудете ее скопировать, ошибка «алиасинга» данных не просто так одна из самых распространенных в программировании.
Как можно «забыть скопировать строку для изменения», переданную по const &?
Использовать стандартные контейнеры без указателей на них возможно только в примерах
Как-то не доводилось работать с контейнерами по указателям, хоть сырыми, хоть умными. Только по ссылкам. Возможно, вы просто мало хорошего кода на с++ писали?
Забыть скопировать строку можно если она не передана по const&, а сидит в структуре данных по указателю. А как вы работаете со сложными структурами данных без указателей? Пересоздаете всю структуру если нужно заменить один объект на который она ссылается? Нет, можно писать программы и без указателей и даже без единого побочного эффекта, но зачем для этого использовать C++?
Или если один и тот же шаблон в разных исполняемых файлах и/или динамических библиотеках, то это просто дублирование одинакового кода.
«Библиотечными» являются только фунции подсчета ссылок (которых в STL попросту нет) и управления памятью. Так еще раз, что именно в STL раздувает код в сравнении с контейнерами Qt?
а в нагрузку еще дополнительное времени на отладку и сопровождение этих решений
Допустим, я умею передавать объекты не только по значению, но и по различного вида ссылкам. Зачем мне COW?
как вы работаете со сложными структурами данных без указателей? Пересоздаете всю структуру если нужно заменить один объект на который она ссылается?
Если я ссылаюсь на один элемент контейнера, я беру ссылку на него. Необходимости хранить эту ссылку обычно нет.
Qt это единственная библиотека GUI на C++ имеющая полный набор необходимый возможностей. То что она не использует контейнеры STL, трудно назвать недостатком.
а теперь возьмите напишите библиотеку на Qt и попробуйте её распространить для использования в приложениях с и без Qt. Без открытия исходного кода. И вам пользователи быстро объяснят где же вы не правы.
использование слова «стандартные» (т.е. из коробки) выдает брехуна с головой.
работать на более высоком уровне задач, а не функцийen.cppreference.com/w/cpp/thread/packaged_task, к примеру.
Не надо хамить. Если Ваше мнение не совпадает с моим или ответ показался Вам неполным — это ещё не значит, что можно делать те поверхностные выводы, которые Вы спешите делать.
ломать голову, как скрестить буст с QEventLoopНу я предполагаю, что разработчики Qt об этом позаботятся и, выкинув свои велосипеды, сделают удобную поддержку чего-то другого (стандартного, например). Это и есть изначальный посыл: в Qt, кроме GUI нет ничего стоящего по современным меркам, так не лучше ли выкинуть велосипеды и сделать, где надо, интеграцию с внешними либами.
сложность от необходимости изучения нескольких API с лёгкостью покрывается сложностью написания многопоточного кода вообще.Согласен.
Я сомневаюсь в том, что человек говорящий загадками что- то реально знает.Не вам судить. Так-то Вы вообще компилятор и стандартную библиотеку путаете:
файловую систему (которую пока компиляторы не реализовали)
Вы надеюсь в курсе, что весь Qt потихоньку перетекает в QML, который буквально является другим языком?
Современный интерфейс требует программирования (а не набрасывания элементов на форму), чтобы можно было его программно менять. Только поэтому внедрили QML. Ничего более, чем реализовать интерфейс на QML нельзя.
QML — да, но это же не весь Qt, к моему сожалению.
А теперь представьте, что было бы, если бы в C++98 добавили, ну например, асинхронный IO, примерно соответствующий возможностям select из POSIX. Каковы шансы на то что он угодил бы хотя бы той же доле, которой угодил std::string?
для чего С++ менеджер пакетов?Чтобы быстро собрать нужные библиотеки без огладки на ОС. Почему в мире Python, Ruby, Java и Rust-а это делается «по щелчку», а в мире C++ — нет?
что бы каждую либо вынести отдельно?Как будто в этом есть что-то плохое.
вы предлагаете пакетный менеджер и для С++ что бы так страдать?Я не понял причины ваших страданий и не понял, почему вы страдания из Python-а пытаетесь перенести на C++.
Мне, например, неудобно, что под Ubuntu нужно подключать зависимости через apt, на Arch-е через pacman, на FreeBSD через pkg, а под Windows через vcpkg. Хочется что-то хорошее, вроде Rust-овского Cargo, чтобы не было привязки к пакетным менеджерам конкретных ОС.
если разобрать весь std на отдельные либы по хидерамНе нужно дробить std. А вот возможность подключать к себе чужие библиотеки через простое описание зависимостей — это очень ценно и удобно.
Если С++-проект существует в таких же условиях(в которых существует раст-проект), то никаких особых проблем не возникает, особенно в контексте тех же header-only зависимостей. Носим зависимости с собой, либо живые по субмодулям.
Какую-то значительную часть кода всё равно не перевести на новые рельсы, особенно учитывая то, что в мире С++ очень много системных сишных зависимостей.
Будут только новые заморочки с сомнительной полезностью.
то никаких особых проблем не возникаетСказки только не нужно рассказывать. Приходится либо возможности VCS использовать, либо делать свои велосипеды для того, чтобы подтаскивать зависимости одинаковым образом вне зависимости от платформы.
Сказки только не нужно рассказывать.
Расскажи о возможных проблем в ситуации той, которую я выше описал. Интересно послушать.
Приходится либо возможности VCS использовать
Это какая-то проблема? Или это нельзя использовать? Чем установка на таргет vcs отличается от установки cargo? Ничем? А использовать надо что-то в любом случае.
Расскажи о возможных проблем в ситуации той, которую я выше описал.Простите, но вы ничего не описали. Конкретики не было. Но если хотите показать, насколько все хорошо, то расскажите, как организовать управление зависимостями для кросс-платформенного проекта, который должен использовать, скажем, Boost (MultiIndex, Spirit), ACE, Catch и spdlog.
Boost (MultiIndex, Spirit), Catch и spdlog.
Всё это есть на гитхабе. Добавляем их в субмодули, закинув в какое-нибудь third_party, указывая нужную ветку. Далее забиваем пути к инклюдам каждого пакета в компилятор руками. Обычно через cmake.
С ACE будет сложнее, но это проблемы ace и пакетный менеджер ей никак уже не поможет. Это просто дремучие легаси. Еслиб это был какой-нибудь standalone asio, то никаких проблем не возникает(так же, как и со всем, что выше).
Всё это есть на гитхабе. Добавляем их в субмодулиА вот вы попробуйте. Я попробовал взять Boost.Interprocess и нужные ему зависимости. Оказалось, что вытащить цепочку нужных частей Boost-а непросто. И даже специально разработанная для этого утилита не всегда точна.
Так что потрындеть на форуме, так все в шоколаде. А когда до дела доходит, то начинается геморрой. От которого вы предпочитаете отмахиваться фразами вроде «Это просто дремучие легаси».
А вот вы попробуйте.
Пробовал, не волнуйтесь.
Я попробовал взять Boost.Interprocess и нужные ему зависимости. Оказалось, что вытащить цепочку нужных частей Boost-а непросто.
Не вижу смысла тащить нужное, там всё равно утащится пол буста.
Делается за минуту pastebin.com/raw/mTsJ87hA без всяких проблем. Первый попавшийся пример успешно собирается.
И даже специально разработанная для этого утилита не всегда точна.
Точности всегда можно добавить руками, это нужно сделать один раз.
Так что потрындеть на форуме
Вы мне дали список, я вам сообщил, что никаких проблем нет. Вы начали ссылаться именно на «потрындеть», обвиняя меня в том же самом. Какой в этом смысл?
А когда до дела доходит, то начинается геморрой.
Геморрой приходит потому, что изначально что-то используется не так, и что самое интересное, разговор был не об этом. Если упомянутое вами ACE не ушло с gnumake до сих пор, то ни на какое «карго» они не перейдут.
Тоже самое и c бустом, проблема организации буста — проблема буста. Да, придётся потратить( один раз) на пару минут больше времени, чем с нормальной автономной ho библитекой, но опять же — это не проблема.
От которого вы предпочитаете отмахиваться фразами вроде «Это просто дремучие легаси».
Естественно, а иначе никак. У вас нет вариантов. В расте нет дремучего легаси и каждый пакет сам отвечает за себя. И если ваш легаси-проект не может уйти от легаси, то ни в какой пакетный менеджер он не уйдёт. Это очевидно.
И я сразу написал, что если использовать нормальные вещи — никаких проблем не будет. И их действительно нет. А проблемы не нормальных вещей — это проблема только их и их пользователей. И это могут исправить только сами вещи и никто иной.
Вам нужно учитывать контекст, вы должны показать и рассказать, каким образом при создании для C++ cargo ACE уйдёт на карго. Какое у вас основание так думать? Ничего к этому не располагает.
А забыть о контексте, о ваших же примерах и потом крыть «ну дак проблемы бывают» — бывают, везде. И вопрос не в самих проблем, а в том решении(карго), что предлагаете вы. Вам нужно не просто обвинить моё решение, но и показать то, каким образом ВАШЕ решение это обойдёт. Это очевидно.
Пробовал, не волнуйтесь.Волнуюсь, поскольку сомневаюсь, что пробовали.
Не вижу смысла тащить нужное, там всё равно утащится пол буста.25 библиотек — это не полбуста, это меньше четверти. Ну и если вы не видите смысла, это не значит, что все согласны с вашими взглядами.
Точности всегда можно добавить руками, это нужно сделать один раз.В этом и фокус: каждому разработчику это нужно будет делать, минимум, один раз для каждого своего проекта. Это непродуктивно.
Вы мне дали список, я вам сообщил, что никаких проблем нет.«Я вам сообщил» — это теперь такая форма доказательства? Не срабатывает.
И если ваш легаси-проект не может уйти от легаси, то ни в какой пакетный менеджер он не уйдёт. Это очевидно.Для вас может быть и очевидно. А вот опыт vcpkg показывает, что не очевидно. Порты vcpkg можно делать даже для библиотек, которые про vckpg ничего не знают.
Вам нужно учитывать контекст, вы должны показать и рассказать, каким образом при создании для C++ cargo ACE уйдёт на карго.Вот прямо таки должен? :))) Вы что-то путаете. Есть много людей, которые находят неудобным отсутствие менеджера зависимостей в C++. Я думаю, что ваш совет управлять зависимостями через git submodules они проигнорируют, а вот что-то из vcpkg/conan/hunter попробуют.
Это очевидно.Очевидно, что вы заблудились в словах. Проблема в том, что в C++ нет ничего подобного на Cargo/Maven/RubyGems. И вторая проблема в том, что есть персонажи (вы среди них), которые считают, что это не проблема.
Хорошо бы сперва прийти к тому, что отсутствие штатного (де-факто стандартного) менеджера зависимостей для C++ это проблема. В этом я и хочу убедить собеседников. А вовсе не в том, что именно Cargo нужен C++.
25 библиотек — это не полбуста, это меньше четверти. Ну и если вы не видите смысла, это не значит, что все согласны с вашими взглядами.
Взгляды надо обосновывать, если ваши взгляды претендуют на объективность. При этом в ситуации, когда вы утверждаете нужность чего-то, то именно вы и должны эту нужность обосновывать. Любая вещь ненужна по умолчанию.
В этом и фокус: каждому разработчику это нужно будет делать, минимум, один раз для каждого своего проекта. Это непродуктивно.
Нужно делать что? Заполнять зависимости вы будите в любом случае, никакой разницы нет.
А далее вы опять игнорируете неудобные моменты. Вы рассказывали о какой-то сложность, каких-то проблемах и я вам показал, что это решается за 1минуту. Максимум за 5. Т.е. никаких проблем нет. Ваши претензии были необоснованными, а раз уже есть прецедент, то всё остальное я могу записать туда же, пока вы не докажете обратное.
Кстати, расскажи, сколько у вас проектов? Если 5минут для вас проблема, то их должны быть десятки, сотни в день. Что очень сомнительно, и эти сомнения вы не развеяли.
«Я вам сообщил» — это теперь такая форма доказательства? Не срабатывает.
Я ничего кроме сообщений от вас не вижу, в чём смысл меня обвинять, если делаете тоже самое?
При этом, я уже вам отвечал и даже показывал как. Вы же ничего не показывали, ничего не ответили, а просто сей факт проигнорировали.
Для вас может быть и очевидно. А вот опыт vcpkg показывает, что не очевидно. Порты vcpkg можно делать даже для библиотек, которые про vckpg ничего не знают.
Вы сами будите поддерживать эти порты? Зачем вы говорили о карго? У вас каждую секунду появляется новое обстоятельство. Вы уже перевели ace на нормальную систему сборки, либо кто-либо другой? Нет, дак какой может быть разговор?
Так что потрындеть на форуме, так все в шоколаде. А когда до дела доходит, то начинается геморрой. От которого вы предпочитаете отмахиваться фразами вроде «всё сработает».
Вот прямо таки должен? :))) Вы что-то путаете.
Не путаю, если не должны «потрындеть на форум», а вот «не потрындеть» должны.
Есть много людей, которые находят неудобным отсутствие менеджера зависимостей в C++.
Дальше что? Мы обсуждаем ваши, либо чьи-либо рассуждения об удобстве. Мы обсуждаем именно то, что в современных реалиях нет никаких проблем. Вы утверждали обратное, пока безуспешно.
Я думаю, что ваш совет управлять зависимостями через git submodules они проигнорируют, а вот что-то из vcpkg/conan/hunter попробуют.
И флаг им в руки, дальше то что?
Очевидно, что вы заблудились в словах.
Заблудились именно вы.
Проблема в том, что в C++ нет ничего подобного на Cargo/Maven/RubyGems.
И вам сообщили о том, что никто подобного быть в принципе не может т.к. мир С++ состоит из легаси, именно у легаси проблемы с дистрибуцией и сборкой. И именно им и нужен пакетный менеджер. Но они на него не пойдут, т.к. если бы хотели — уже бы ушли хотя-бы с gnumake, а пока это трындёж на форуме.
И вторая проблема в том, что есть персонажи (вы среди них), которые считают, что это не проблема.
Это не проблема, т.к. она ничего не решит. Вы попытались ссылаться и на «авторам не обязательно переводить» и на существующие ныне пакетные менеджеры и тут возникает вопрос — а почему же вы не на пакетном менеджере, как и ваши зависимости?
Те, кому это интересно — уже давно на standalone ho, т.е. они пытаются решить и решают проблемы. Вы же её не решаете и решать не пытаетесь, а все ваши рассуждения сводятся к тому, что «вот дадут нам официальный ПМ — весь код сразу на нём будет». Чем это обосновано? Никто не знает.
К тому же, я не только считаю, но и показываю почему. Вы начали про Boost.Interprocess, и вам оказалось сложно. Но мне почему-то оказалось не сложно. Может всё же ваше «сложно» не очень объективно?
Хорошо бы сперва прийти к тому, что отсутствие штатного (де-факто стандартного) менеджера зависимостей для C++ это проблема.
Это абсолютно неважно. Важно то, что его наличие ничего не изменит. Для тех, кто использует беспроблемные техники — ничего не изменится. Для тех, кто использует проблемные — так же, ведь основная причина их проблемы в том, что они легаси. Если легаси уже 20лет как легаси, то никакой новый, модный ПМ им не поможет.
В этом я и хочу убедить собеседников. А вовсе не в том, что именно Cargo нужен C++.
Вы не понимаете простой вещи. В языка с ПМ есть не ПМ, а нечто иное. Он там был всегда. В рамках МП мыслят создатели библиотек, пользователи библиотек. Это не просто МП — это система дистрибуции. Для компилируемых языков — это ещё и система сборки. Очередной МП вам не даст того же, что даёт карго.
И даже если у нас появится этот самый ПМ — никакое легаси на него не переберётся. Рассчитывать неких волонтёров не приходится. Не нужно сравнивать с vcpkg и прочим — это просто набор скриптов поверх базовой системы сборки, который не даст той просты, той унификации, которую даёт cargo и ему подобные.
Сколько лет уже буст пытаются перевести на cmake? Много. Кто-то левый возьмётся это делать? Сомневаюсь.
Вот и получится так, как получилось со всеми левыми ПМ. То, что уже нормально работает туда добавили, а все сложные легаси вещи, с которыми и существуют основные проблемы — нет. И магическое слово «стандартный» мало что изменит.
Вы говорите, что мир С++ состоит из легаси, легаси не будет использовать новую стандартную систему дистрибуции, а значит не нужно её создавать. Я думаю, такая позиция будет откровенно вредной для людей, которые занимаются разработкой и внедрением новых фич в С++ с целью его развивать и улучшать, а не готовить к постепенной деградации.
Да, какое-то легаси будет переводиться на новую систему дистрибуции дольше, чем выходит HL3, но почему это должно влиять на новые проекты?
Старые проекты будут или не будут использовать новый ПМ в зависимости от соотношения профит/трудозатраты, а создатели новых проектов будут «мыслить в рамках нового МП». Если систему модулей, менеджер пакетов и реппозиторий пакетов смогут внедрить придерживаясь принципа «не платишь за то, что не используешь», то в этом со всех сторон будет одна лишь польза. Разве не так?
Ваша позиция напоминает поговорку «не жили богато, нечего и начинать».
У вас очень странные представления. Лично я считаю, что это новое — это деградация.
Я выше писал, но повторю более полно. С выкидыванием такого понятия как cpp-файл — решаются все проблемы. Со сборкой, с линковкой, с дистрибуцией зависимостей, с переносимостью. Выше я всё это разбирал.
Мало того, он получился ещё и быстрее, ведь компилятор может лучше оптимизировать код. Для дефолтного подхода начали пытаться реализовывать оптимизации на стадии линковки. Это прогресс? Нет, это трата времени и сил на тупиковый легаси-подход.
Сейчас нам предлагают модули. Да, они лучше легаси-подхода, но лучше ли они инклюдов? Я не вижу, не вижу в чём лучше. Вижу только хуже. Инклюды обладают полной прозрачностью:
Они существуют на уровне языка( в отличии от всех внешних приключений в случаи раздельной сборки).
Они позволяют получить/изучить/модифицировать код. Вам не нужно изучать внешние костыли и заморочки каждого конкретного проекта — всё тут, всё в общем виде.
И это только начало. Пунктов ещё много. Модули опять откатят нас в 80е года, но сейчас у нас есть надежда — ide, которая нам будет эмулировать инклюды.
Пакетный менеджер — он всё равно нам ничего не заменит. У нас есть система для хранения/дистрибуции кода — гитхаб и иже с ним. Нам нужна будет vcs, она у нас есть. Опять же, есть гитхаб для работы с vcs. У нас есть всё.
Система сборки в полной мере не нужна. Она остаётся как костыли для решения всяких платформозависимых проблем, но мы уже давно пытаемся от них уйти.
И что же нам действительно нужно? Нам нужны альтернативы костылей на макросах. Сбора информации о системе, условная компиляция.
Люди пытаются пропихнуть модули, рассказывая о плохих макросах, но. Кто-то дал людям до модулей альтернативу? Какие-то минимальные подвижки есть — тот же порядок байт и прочее, но это лишь крохи.
Модули не дадут никакого разительного преимущества по части времени компиляции, по части упрощения разбора кода. Есть подвижки в сторону действительно революционной вещи — инкрементальной сборки? Которая даст невероятный буст. Нужны компиляторы-сервисы, которые будут жить постоянно, постоянно инкрементально пересобирая программу.
И тут уже будут инклюды, тут уже не будут нужны никакие системы ускоряющие сборку/следящие за обновлением файлов, никакие модули. Я вижу в этом прогресс, а не в модулях/МП«х и прочем, что ничего по сути не даст, а только откатит нас назад.
не платишь за то, что не используешь
Платишь. Ресурсы людей не безграничны. К тому же, модули никогда не будут так же удобны и прозрачны как инклюды.
В общем, спасибо что подробно всё расписали. Есть над чем подумать.
Никто(в частности я) не спорит с тем, что это удобно. Я просто не вижу вариантов в которых он внесёт какие-то заметные изменения в реалии, в частности мои. Слишком много нужно сделать, причём с очень сомнительным профитом. В этом моя претензия.
К тому же, я просто не представляю как в С++ мире может существовать какай-то аналог карго. У всех языком с ПМ зачастую один единственный тулчейн. Питон, жава, жс, раст. Да, там есть какие-то альтерантивы, но они очень нишевые и их 1-3 штуки. Как это вообще должно работать во всём это зоопарке — решительно непонятно.
1. Подтащить нужные вам зависимости. Например, вам нужна библиотека A версии 1.2.3 и библиотека B версии 2.3.4. А так же все их зависимости. Желательно с проверкой конфликтов (скажем, если A зависит от G версии 3.4.5, а B — от G версии 2.8.9, причем G-3.4.5 не совместимы с G-2.8.9).
2. Сборка всего этого хозяйства.
Один подход состоит в том, чтобы пытаться увязать это все вместе. Например, vcpkg и (насколько я знаю) hunter требуют поддержки CMake от проектов. С помощью vcpkg/hunter вы вытаскиваете зависимости и эти зависимости становятся вам доступны без лишних усилий, если вы используете в своем проекте CMake. По аналогичному пути пошли разработчики build2. Там вообще все в одном флаконе — и зависимости, и сборка.
Другой подход состоит в том, чтобы разделись управление зависимостями и сборку. По этому пути сейчас идет conan, который, как и его предшественник, biicode был изначально привязан к CMake, но сейчас это уже (вроде как) не обязательно.
Моя точка зрения состоит в том, что два эти вопроса нужно рассматривать раздельно. По крайней мере сейчас.
В вопросе системы сборки в настоящее время прослеживается явная тенденция к тому, чтобы де-факто стандартом стал CMake. По большому счету, новые проекты изначально стараются поддерживать CMake, старые потихоньку адаптируются под CMake или же CMake-файлы для них делают те, кто вынужден использовать старые проекты. Тенденция достаточно заметная и устойчивая, активно поддерживается производителями самых заметных IDE. Так что со временем вопроса как собрать проект X не будет — если этот проект более-менее жив, то для него где-то будет CMake-файл.
А вот с вопросом описания и подтаскивания зависимостей не так все просто. Но вот vcpkg показал, что port-файл для проекта X можно создать даже не вмешиваясь в сам проект X. Правда, при этом у vcpkg есть странные родовые травмы, которые вызывают сомнения в перспективности самого vcpkg. Но вот то, что в vcpkg можно засунуть любой проект, для которого доступен тарболл — это знаковый показатель.
Причем, в вопросах управления зависимостями нужно различать несколько аспектов. Во-первых, собственно, сам транспорт. Где будут складироваться пакеты, как они будут доставляться? Во-вторых, расположение загруженных пакетов — внутри вашего рабочего каталога, снаружи. Должен ли однажды загруженный пакет быть доступен любым вашим проектам на этой машине. Или же он должен принадлежать только одному вашему проекту.
В зависимости от ответов на эти вопросы можно выбирать и инструментарий для реализации управления зависимостями. Скажем, озвученный выше подход с git submodules вполне себе будет рабочим в определенных условиях. Как-то: вы работаете с git-ом (а не с другой vcs), ваши зависимости должны принадлежать только одному вашему проекту.
Но если вы хотите, чтобы однажды загруженный boost-1.67 был доступен всем вашим проектам на конкретной машине, то нужен какой-то другой подход.
Как раз эти подходы сейчас и исследуются в рамках разных инструментов (коих не так уж и мало: vcpkg, conan, hunter, cppan, build2, buckaroo). Что из этого выживет и какие даст плоды — будем посмотреть, только время сможет дать ответ.
Но работа идет. И идет она для того, чтобы некий условный Вася Пупкин (особенно если он начинающий C++ программист) мог написать в своем проекте:
deps: A-1.2.3, B-2.3.4
а некий удобный в использовании инструмент ему это в проект подтянул со всеми зависимостями. Что уже будет в основе — git submodules, родные менеджеры зависимостей конкретных ОС, единый репозиторий на машине разработчика и т.д. — это уже вопрос реализации.
И каких-то принципиальных технических препятствий для достижения такого результата я лично не вижу. Тут, скорее, главное препятствование — это вопли о том, что все это нинужно и ниасуществимо :)
Мне кажется, что в общем виде эта задача нерешаема средствами упомянутых языков, просто потому, что компановка исполнимой программы является внешней службой, не имеющей прямого отношения к языку программирования. И C, и C++ работают с единственной единицей компиляции за раз для создания объектного файла. Оставляя вопрос создания целостного исполнимого бинарного образа компановщику, как части операционной системы.
Во всяком случае, создание единой системы управления бинарными и сборочными зависимостями для сборки «абстрактного» отдельно взятого приложения — нерешаемо в обозримой перспективе. Поскольку для этого надо, чтобы все приняли одно из частных решений: какой-то конкретный вариант «песочницы», «бандла» и т.д. Или же потребовать интеграции почти всех бинарников в единое дерево (пресловутый UNIX way). А поскольку каждый из нас Бетховен…
Для unix way существует много менеджеров пакетов, которые с практической точки зрения можно считать изоморфными, и все эти способы вполне работоспособны. В Windows и MacOS есть более-менее общепринятые способы создания «песочниц». В MacOS homebrew, например, предоставляет вполне работающее средство для создания согласованного дерева бинарных (в широком смысле) компонентов вместе с необходимыми зависимостями сборки. Новые языки вроде Go и Rust тяготеют к статической компоновке, при этом Go в данный момент пытается стандартизировать формирование согласованного дерева исходников для сборки, а в Rust понятие модуля (несущественно, сколь совершенное) существует на уровне языка (что и делает возможным существование Cargo).
Ну, а идею «модулей» для C++ без предварительной стандартизации ABI я полагаю химерой разума и причудой бальзаковского возраста. Моя точка зрения, конечно, «голос с белтА», но «высоколобые гуру языка C++» в очередной раз занялись своей высоколобой фигней для того, чтобы не думать о более трудных и насущных проблемах языка. О чем Страуструп периодически говорит, но кому интересно его мнение…
Имхо, тут нужно решать проблему по частям. Сперва разобраться с зависимостями, которые представимы в виде архивов исходников. Т.е. менеджеры, которые позволяют, грубо говоря, автоматически скачать по необходимости A--1.2.3.tar.bz2, B-2.3.4.tar.bz2 и все нужные им *.tar.bz2, распаковать это куда-то и сказать пользователю: все, все твои зависимости в твоем распоряжении, дальше сам.
Т.е. дальше уже сам C++ разработчик занимается компиляцией, линковкой и развертыванием получившихся бинарников в соответствии с соглашениями конкретных ОС или собственными пристрастиями.
Да, это не полноценное решение. Но, по нашему совсем скромному опыту использования собственного лисапеда, это сильно лучше, чем ничего.
PS. Модули C++ я предпочитаю в этом контексте вообще не обсуждать. Ибо стараюсь не бежать впереди паровоза. Когда завезут модули в C++, тогда и будем с этой проблемой разбираться. Все равно это произойдет не сегодня и не завтра.
Новые языки вроде Go и Rust тяготеют к статической компоновке, при этом Go в данный момент пытается стандартизировать формирование согласованного дерева исходников для сборки, а в Rust понятие модуля (несущественно, сколь совершенное) существует на уровне языка (что и делает возможным существование Cargo).
И это самое правильное решение, собирать каждую программу в свой бинарник. Попытки всё линковать динамически имеют слишком много проблем и крайне сомнительный профит.
Моя точка зрения, конечно, «голос с белтА», но «высоколобые гуру языка C++» в очередной раз занялись своей высоколобой фигней для того, чтобы не думать о более трудных и насущных проблемах языка.
Я выше приводил пример. Гуру пытаются пропихнуть модули, критикуя макросы. Указывая на макросы как проблему, но. Пытаются ли они дать людям альтернативу. Как реализовать без макросов условную компиляцию? Как реализовать кодогенерацию без макросов?
Вот и получается, что даже если есть какой-то новый проект, которому нужен функционал макросов(а таких много), который захочет на модули и захочет красиво. Что делать? Неясно.
if constexpr для простых случаев
Это не условная компиляция даже близко.
использование разных .cpp-файлов в рамках билдсистемы в сложных.
Т.е. в рамках языка никак. Накостылить сбоку всегда можно, но это не значит что что-то есть.
Compile-time reflection, пропозалы есть, работа ведётся.
Судя по тому, что я смотрел — скудно. Очень скудно. Её уже пол десятка лет обещают. Но это хоть что-то.
Опять же, сугубо в моём опыте, условная компиляция нужна только при написании платформозависимого кода, что и так выходит за рамки языка.
Не выходит. Ситуация «нужен разный функционал в зависимости от условий определённых на стадии компиляции» существует в рамках языка. Применяется везде и всюду, только в боле слабом виде. Просто пример — я хочу сконфигурировать либу, чтобы у меня не комплиировались километры лишнего кода. Сейчас я этого сделать не могу, если только макросами.
К тому же, С++ это такой язык, где много платформозависимого кода. Это только чисто формально он «кроссплатформенный».
Чего вам там не хватает?
Кодогенерации. Хочу не только читать, но и писать. Какие-нибудь хуки. Допустим — вызывать что-то вызове функции, при выходе из функции, вызывать что-то при определении какой-то класса. Много чего можно сделать с рефлексией, что улучшим мою жизнь.
Я подозреваю, что влияние модулей на время компиляции будет сопоставимо с прекомпилированными заголовками.
Вот время компоновки может сократиться очень существенно, это да. Но проблемы макросов и транзитивных зависимостей — Вам ведь знакома ситуация, когда надо использовать динамическую библиотеку, собранную с другой версией рантайма?
Поэтому в ситуации с нормальной организации кода и библиотек — никого профита, кроме какой-то экономии трафика/мета не зафиксировано. И то, далеко не факт, что что-то будет вообще сэкономлено в сравнении со стоимостью ПМ.
вы просто пишете find_packageАх если бы find_package работал как надо, не нужны были бы пакетные менеджеры. Не всегда дистрибутив имеет рабочую версию нужной либы в нужной версии. А так приходится писать find_package а затем if not_found — использовать своё из thirdparty.
По сути, hunter — это попытка сделать find_package, который бы работал на всех дистрах/платформах.
мало кто из проприетарных товарищей пакетируют софт под арчНо такая возможность есть и некоторые мейнтейнеры портируют бинари из других дистров, что решает проблему.
страдания в питоне — почему я должен ставить толстый менеджер пакетов только что бы добраться до нескольких небольших библиотек?Может это конкретно проблема Python-а и PIP-а. В Ruby на RubyGems народ не жаловался, в Rust-е на Cargo не жалуются, в Java с Maven-ом вроде как так же не жалуются.
зачем дробить текущий С++ библиотеки мелкие пакеты ради какого то менеджера пакетов?О дроблении каких библиотек идет речь?
Хорошо бы раздробить Boost, поскольку он является не одной библиотекой, а конгломератом из более чем сотни разных библиотек.
Но вот кто хочет дробить ACE? Или POCO? Или Botan?
менеджер пакетов для С++ в моем понимании это некая доп утилита рядом с компилятором, которая позволит стягивать/устанавливать свои cpp/h файлы
так?
Не свои, а чужие. И желательно именно исходные файлы чужих библиотек, чтобы их можно было собирать под себя.
поэтому лучше стянуть весь бустЛучше вытянуть 120 библиотек, чем 20 библиотек? Wow. Тут крыть нечем.
я не вижу профита в менеджере который стягивает другие библиотеки, при том что другие библиотеки я могу стянуть и самВы, видимо, очень трудолюбивый человек. Я бы предпочел, чтобы за меня это сделал какой-то удобный инструмент.
менеджер пакетов как некоторое облако в которое все существующие библиотеки С++ авторы должны будут переделать и залить?Лучше иметь какой-то формат описания пакета и его зависимостей. А так же, возможно, централизованный репозиторий таких описаний. Выкладывать же тарболлы можно так, как удобно разработчикам библиотек. Инструмент должен поддерживать несколько способов получения тарболла (что не так уж и сложно, если ограничится поддержкой именно tar.{gz,bz2,xz}, zip, 7z, репозиториев git, hg и svn).
очень сомневаюсь что они это будут делатьЭто сильно лучше, чем заниматься опакечиванием своих библиотек для текущего зоопарка (deb, rpm, pkg, homebrew, vcpkg, conan, hunter и пр.).
они уже есть в apt-get/pkg/vcpkgСуществование вот этих инструментов вам кажется оправданным?
apt-get/pkg — оправданыПожалуй, нет. Поскольку очевидно, что за пределами отдельных Unix-ов для вас жизни нет.
vcpkg не оправдан в ввиду сложности скачивания нужного пакета без vcpkgИнструмент X не оправдан, поскольку он не предполагает работы без инструмента X? Странный взгляд на реальность.
Но меня интересует другое: если вы в принципе признаете целесообразность существования таких вещей, как apt-get, pkg, vckpg, conan и пр., то почему бы не сделать следующий шаг и не ответить на такой вопрос: «Зачем иметь весь этот зоопарк вместо одного штатного менеджера зависимостей?»
штатный менеджер зависимостей будет где то в сторонке«штатный» и «в сторонке» — это несовместимые понятия. Это как с CMake. Если библиотека собирается CMake, то можно, конечно, обойтись без CMake и написать скрипты для сборки этой библиотеки под свою систему сборки. Но это не штатный сценарий использования библиотеки.
Теперь по сути. У нас есть двухлетний опыт использования своего велосипеда для кроссплатформенного управления зависимостями. Этот велосипед может поддерживать как тарболлы, так и брать версии из git/hg/svn (как head-ревизии, так и конкретные ревизии). И этот опыт показывает, что когда можно в зависимостях указать тарболл в 1Mb или даже в 5Mb, то он скачивается и разворачивается за считанные секунды. Если же нужно тянуть конкретную ревизию из git-а или hg, да еще из репозитория с длинной историей, когда выкачиваются десятки мегабайт, тогда все становится намного более грустно. Подтягивания зависимостей длится не 3-4 секунды для среднего проектика, а 30-40 секунд и более. Если нужно сделать пару-тройку клонов проекта для проверки каких-то версий (мы используем hg, там проще клонами, а не бранчами), то как-то грустно сидеть и ждать это время.
Так что если есть возможность скачать 10Mb зависимостей вместо 100Mb, то я предпочту скачать 10Mb. Насколько бы лично вы не видели проблем в скачивании 100Mb.
Так вы буст из гита что ли берёте?Буст мы вообще редко используем. Был эксперимент в том, чтобы брать его из git-а, раз уж его попытались разрезать на модули.
Кроме того, откуда прикажете брать Boost-1.67 под Ubuntu 16.04?
У меня такое чувство, что ваш велосипед немножко сломанныйУ меня чувство, что вы здесь потрындеть не включая мозги, отсюда и такие комментарии, на которые, дабы ответить обстоятельно, приходится тратить массу времени.
Велосипед такой, каким он и был задуман. Он собирает зависимости только в рабочий каталог конкретного проекта. Без каких-либо попыток создать что-то вроде общего репозитория на машине разработчика (как это делает conan, к примеру). Нам такой подход привычнее и удобнее. И мы никому его не навязываем.
так что обобщать проблемы вашего велосипеда на всё плюсосообщество как-то странно.Хотелось бы узнать, где мы обобщаем. Пока что сухой остаток от дискуссии в том, что многим активным персонажам заточенный под C++ менеджер зависимостей просто не нужен, т.к. они довольствуются тем, что есть в конкретных дистрибутивах Linux-ов, а на весь остальной мир начхать. Как по мне, то это плохо.
это монолит потому что каждая из конгломерата использует соседаИ это не проблема. Scikit-learn использует Scipy и numpy, куча всего в C++ зависит от Eigen, boost и т.д. Транзитивные зависимости — это не страшно. Уже то, что можно использовать numpy без scipy — плюс. Также и с boost, было бы неплохо иметь возможность использовать core без остального табора.
поэтому лучше стянуть весь буст
А зачем столько много дистрибутивов?ХЗ, вот расплодились отчего-то. Если я пишу программулину, которая может работать и под Linux, и под FreeBSD, и под Windows, то каким дистрибутивом Linux-а мне нужно ограничится?
Если программулина опенсорсная, то тем, под который вы её сами адекватно поддерживать сможете.Ну вот, например. Нужна 3-4 калекам во всем мире. Не вижу препятствий к тому, чтобы без проблем баловаться с ней под разными Linux-ами. И не вижу смысла прибивать ее гвоздями к одному какому-то.
За исключением того, что в Linux-ах разные менеджеры пакетов. И разные пакеты в родном менеджере доступны в разных версиях.
Что вы предлагаете делать в таком случае?
Вопросов больше не имею. Если C++ников с такими взглядами на управление зависимостями большинство, то проще свалить нахер в мир Rust-а и забыть все эту плюсовую помойку вместе с ее адептами как страшный сон.
неудобно, что под Ubuntu нужно подключать зависимости через apt, на Arch-е через pacman, на FreeBSD через pkg, а под Windows через vcpkgЕсли бы только неудобно, у них же вечно разный набор доступных пакетов/версий и вечно этого набора не хватает и требуется адаптировать сборку под каждый дистр что бы добиться совместимости с инфраструктурой дистра.
В идеале пакетный менеджер дистра должен интегрироваться с пакетным менеджером языка — не должно быть разницы между
apt-get install python-numpy
и pip install numpy
В идеале пакетный менеджер дистра должен интегрироваться с пакетным менеджером языка — не должно быть разницы между apt-get install python-numpy и pip install numpy
Спорно. У всех своё понимание стабильности. Представьте вы в доживающим свой срок релизе Дебиана обновите из pip пакеты…
apt-get install python-numpy
в
pip install 'numpy==1.2.3'
Ситауция% есть библиотека А, сорцы открыты, лежит, например, на гитхабе. В библиотеке есть баг, есть issue в трекере, ему уже пара лет, а разработчику не до этого. По-идее, мейнтейнеры могу добавить патч и в пакете будет библиотека без этого бага. Как с таким подходом быть?
В арче есть PKGBUILD который тоже по зависимостям и плану сборки генерит пакет, очень удобно. Ну только зависимости тоже должны быть пакетированы, что обычно не проблема. Преимущество языкового пакетного менеджера в том, что он может быть один на все системы и таким образом (почти) исчезает необходимость поддерживать пакеты для разных систем. Как в случае с pip.
template <typename T>
requires Container<T>()
void foo(const T &c) { // реализация для контейнера
void foo(auto &&val) { // реализация для не-контейнера
Концепты больше как синтаксический сахар (плюс, ускорение компиляции) для SFINAE через enable_if
С++20 на подходе! Встреча в Рапперсвил-Йона