Pull to refresh

Comments 142

Антон, а поднимается ли в комитете вопрос изменения периодичности выхода стандартов С++?
Например, выпускать их не раз в три года, а раз в два года, раз в год или даже два раза в год?

Сейчас получается следующая ситуация: есть некий жесткий дедлайн, ибо если что-то не входит в C++26, то затем придется ждать целых три года. Как раз пример с trivial relocation. В C++26 не попадает, но, возможно, уже в следующем году это предложение будет доработано, ему придется ждать до C++29.

А вот если бы стандарт выходил раз в год, то окончательный trivial relocation мог бы войти в C++27.

Как я понимаю, комитет сейчас работает по "train model" (если не ошибся с названием): в работе постоянно находится N предложений. К некоторой отсечке времени (за полгода-год до финализации) в новый стандарт включаются те предложения, прогресс по котором признан достаточным. А остальные предложения продолжаются разрабатываться.

В этой модели, в теории, без разницы как часто делается отсечка по времени -- раз в три года или раз в два года. Или даже два раза в год.

Выпуск стандарта ещё влечёт за собой накладные расходы - формальное создание особого черновика, сбор коментариев от стран, испраление замечаний, финализация стандарта в вышестоящих инстанциях ISO... Это достаточто ресурсоёмкие процессы

Пока кажется что 3 года - отличный баланс между скоростью выпуска новых фичей и уменьшением мороки для людей в комитете

формальное создание особого черновика, сбор коментариев от стран, испраление замечаний

А разве нет возможности это распараллелить? Т.е. вот произошла отсечка времени, например, летом 2025-го. Некая группа далее занимается обслуживанием бюрократии для оформления текста стандарта. А остальные возобновляют работы над текущими предложениями.

финализация стандарта в вышестоящих инстанциях ISO... Это достаточто ресурсоёмкие процессы

А тут неизбежно возникает следующий вопрос: а так ли важна сейчас для C++ именно ISO стандартизация?

Ну т.е. роль ISO стандарта в начале 1990х была понятна.

Но сейчас-то зачем?

Допустим, будет условная некоммерческая организация C++ Foundation, которая раз в N месяцев выпускает некий свой документ под названием C++YY language specification. И все.

По факту же, всем компиляторостроителям абсолютно похер на содержимое стандарта: есть в стандарте фичи X1, X2, X3, X4 и X5, а мы сделаем поддержку только X1, X3 и X5. Остальные когда-нибудь, когда руки дойдут. Если дойдут.

И смысл наличия ISO-шного стандарта для непосвященных совершенно ускользает в современных реалиях.

А разве нет возможности это распараллелить?

Оно уже распараллелено, насколько это возможно. Однако, есть критические секции, которые не паралеллятся или плохо паралеллятся

а так ли важна сейчас для C++ именно ISO стандартизация?

Как ни странно - да. C++ чуть ли не единственный современный язык программирования, который можно использовать в приложениях, напрямую влияющих на жизнь человека (самолёты, автомобили, медицинское оборудование, ...). А для такого использования нужна ISO стандартизация.

Без этого - потеряется ощутимая часть пользователей

C++ чуть ли не единственный современный язык программирования, который можно использовать в приложениях, напрямую влияющих на жизнь человека (самолёты, автомобили, медицинское оборудование, ...)

Мне казалось, что у Ada там позиции гораздо крепче, чем у C++.

Ну и такими темпами скоро С++у только и останется, что цепляться за ниши, в которых есть формальное требование наличия ISO-стандарта.

Да и то до тех пор, пока каким-нибудь решением американского конгресса директивно запретят использовать Си и C++ под предлогом небезопасности. И начнут вместо применять условый Rust без оглядки на отсутствие ISO-стандарта для оного.

Мне казалось, что у Ada там позиции гораздо крепче, чем у C++.

Вы правы в том, что С++ есть чему получиться у Ada. Это касается требований к языку в части безопасной разработки перед началом его создания, которые отсутствовали у С и С++.

Как ни странно - да. C++ чуть ли не единственный современный язык программирования, который можно использовать в приложениях, напрямую влияющих на жизнь человека (самолёты, автомобили, медицинское оборудование, ...). А для такого использования нужна ISO стандартизация.

А про такую вещь как сертификация кода для для самолетов, автомобилей, медоборудования, атомпрома, военной и промышленной техники вы не забыли? Там ISO стандартизация просто NULL (nullptr :)). Эту сертификацию получить очень сложно. И пока ваш C++ 26 до этого дойдет (да и дойдет-ли) так уже и другие стандарты древними станут. Сертификация касается не только компилятора, но и C++ библиотек и требования там жесточайшие.

... а получить такую сертификацию для программы не на ISO языке в ряде стран вообще невозможно. ISO обязательное условие, но не достаточное

Что касается MISRA и аналогичных стандартов/требований/гайдов - то их делают зачастую всё те же люди из C++ комитета :)

и потом разраб такой, по каким-либо причинам забивает на язык, и возвращается в язык спустя 3 года, и такой сидит и перед ним пролетают килотонны правил, ""так это можно, это нельзя, это было в легаси, так стоп это же теперь в самом новом стандарте" )

Типа сейчас очень просто взять и после C++14 переучиться на C++26. Ага.

Так-то наоборот, если принимать стандарт раз в год, то дельта изменений по сравнению с предыдущим будет меньше.

Типа сейчас очень просто взять и после C++14 переучиться на C++26

Так вообще не нужно переучиваться, так как процесс стандартизации обеспечивает обратную совместимость и не требуется ничего переписывать, из-за того, что в новой версии сломали старое поведение компилятора или стандартной библлиотеки (как это бывает без стандартизации).

Так вообще не нужно переучиваться, так как процесс стандартизации обеспечивает обратную совместимость и не требуется ничего переписывать,

Во-первых, вы смело можете адресовать свои слова оратору выше. Это он чего-то опасается.

Во-вторых, как бы опыт С++11 говорит, что не так все однозначно.

А принятие модулей в стандарт C++20 -- это тоже отдельная песТня.

Принятие стандарта не означает обязательность его использования.

Рано или позно все равно придется переходить.

Нужно переходить не тогда, когда "можно", а тогда, когда без новых фич уже нельзя.

А могли бы вы мне рассказать, что именно вы пытаетесь до меня донести?

Можно посмотреть в истории:

Типа сейчас очень просто взять и после C++14 переучиться на C++26. Ага.

Что принятие стандарта не требует его немедленного изучения и обязательного применения.

Что принятие стандарта не требует его немедленного изучения и обязательного применения.

Т.е. человек 10 лет сидел на C++14, потом пришло время перейти на C++26 и тут вдруг оказалось, что мои слова "Типа сейчас очень просто взять и после C++14 переучиться на C++26. Ага." не соответствуют действительности.

Так я и поверил, ага.

PS. Вы как-то по своему эту фразу восприняли, я не говорил о том, что стандарты нужно изучать по мере их публикации.

Я написал про то, что использованное вами слово "переучиваться" и сам тон комментария намекает на обязательность переобучения на новый стандарт, тока как я пишу про то, что использование фич из новых стандартов опционально.

Более того, например, я точно уверен, что знаю далеко не все фичи и тонкости новых стандартов, но это не мешает мне писать под C++23.

Я написал про то, что использованное вами слово "переучиваться" и сам тон комментария намекает на обязательность переобучения на новый стандарт

Я говорю про свой опыт: мне пришлось переучиваться на C++11, т.к. те же лямбды и variadic templates позволили отказаться от старых приемов.

Затем пришлось переучиваться на C++17, т.к. там и structured binding, и if constexpr, и fold expressions.

Затем пришлось переучиваться на C++20, т.к. там и концепты и тот же operator<=> (с которым есть неочевидные моменты). Короутины еще. Модули.

В C++23 появился deducing this.

Так-то смысл перехода на новый стандарт именно в том, чтобы освоить новые трюки и научиться обходиться без старых.

Приедет C++26 и нужно будет учиться жить с рефлексией.

Я с вами согласен, что использование новых стандартов обязательно требует из изучения :-)

А минорные фичи типа fold expression и deducing this точно требуют именно переучивания?
Имхо, большие изменения были в 11 стандарте, в чуть меньшей степени в 20 и теперь в 26

А минорные фичи типа fold expression и deducing this точно требуют именно переучивания?

deducing this еще не пробовал. А вот по поводу fold expression у меня регулярно бывают моменты, когда глаза на лоб лезут видя как более опытные в современном C++ люди на fold expression делают то, что я бы делал на функциях с variadic-шаблонами и явной остановкой рекурсии.

А теперь возьмем обратный вариант - нужно портировать такое на платформу со старым компилятором. И тут упс, а более опытный в современном стандарте уже не помнит, как деды писали =)

А, есть какая-то книга, где С++ 23 или С++ 20 фундаментально описаны с нуля? Всё, что попадалось — тоненькие по изменениям по сравнению с предыдущими стандартами. А, вот, для начинающих, как бы с самого начала, есть такие? Для предыдущих версий (С++ 11 и ранее) встречал такие — толстые, всеохватывающие. Чтобы не тянуть старые привычные приемы в новую эпоху и что-то там по изменениям из тоненьких методичек пытаться понять по новым механизмам, а как бы снова с нуля изучить язык сразу в новом стандарте с его новыми методами программирования. А?

Не знаю, не интересовался. У меня нет необходимости учить кого-то C++у с нуля. А чтобы самому обновить знания как раз лучше подходят описания изменений в новых стандартах.

Классический же юмор. Только обычно добавляется "за месяц", или "за год".

Ответ - никак.

Не могу согласиться.

Чем дольше оттягивать переход, тем больше кода который не использует новые идиоматические подходы, и больше кода который потенциально будет мешать переходу (хотя это уже маловероятно если не отставать на 9 лет)

Переходить на новый стандарт нужно как можно скорее. Это не значит что нужно использовать вообще все его новшества, но наверное в каждом стандарте есть вещи которые упрощают жизнь и имеют крайне низкое трение даже со стороны консервативных коллег.

Переход на новый стандарт не может быть самоцелью, и если приложение и так работает, то зачем его переписывать?

но наверное в каждом стандарте есть вещи которые упрощают жизнь

так я про это и написал, когда что-то улучшается, упрощается, повышается надежность и т.д.

но ведь нельзя писать на разных стандартах или можно? щас я наверно минус получу, тогда выходит, если обновилась библиотека "OpenSSL" - язык почти похож на коробку с библиотекой "почти" мне кажется, то на новую версию можно и не переходить, обновление языка, касается и безопасности в том числе, а не просто ради удобства что-то изменилось, поведение кодогенератора может отличаться, может быть улучшена поддержка чего-то, мне кажется новый стандарт как и новая версия или некая стабилити всегда свежесть и выйгрыш, да понимаю, есть килотонны кода, но я так попытался подумать в версии как смог

Gosling-Emacs вот например уже не собрать без знаний, "потомучто произошли изменения в кодинге" уже те какие всё как мне кажется уже фатальны на этапе сборки

Хм, как частота выхода стандартов повлияет на их реализацию компиляторами? Не все фичи C++20 еще пришли в тот же mingw, например. Я не говорю уже про C++23, а на дворе уже 2025 заканчивается. По мне так наоборот - пореже бы их выпускали

В том и дело, что стандарт и реальность не просто различаются, а вообще разные миры.

У нас каждый конкретный компилятор в конкретной версии реализуют какую-то часть каких-то стандартов.

В итоге мы не можем просто взять и ориентироваться полностью на стандарт даже если этого хотим.

Хм, как частота выхода стандартов повлияет на их реализацию компиляторами?

Никак.

Первая идея вот в чем. Cейчас есть два момента:

  • спешка перед заталкиванием предложения в стандарт перед дедлайном. Грубо говоря, какой-то пропозал почти готов, но если не принять его сейчас, то он войдет лишь в следующий стандарт через 3 года. Поэтому его могут принять даже не смотря на недоделки. Чтобы затем фиксить то, что недосмотрели;

  • долгая пауза между принятием в стандарт и выходом самого стандарта. Допустим, летом 26-го года какую-то фичу примут в С++29. Но формально она станет частью C++ только после принятия C++29. Т.е. в 2029-ом году.

Если выпускать стандарты раз в год, то тяжесть этих моментов практически нивелируется.

Вторая идея в том, что если комитет таки начнет синхронизировать то, что попадает в документ с тем, что есть в компиляторах, то частые выпусти релизов позволят чаще синхронизировать состояние компиляторов с текстом стандарта. Грубо говоря, сделают поддержку рефлексии в 3-х основных компиляторах в 2027-ом и тут же можно будет обновить C++27 или C++28. А не ждать принятия C++29.

Но в то, что комитет как-то начнет синхронизироваться с разработичками компиляторов я уже не верю. Люди нормально живут в своей парадигме, зачем что-то менять?

Но в то, что комитет как-то начнет синхронизироваться с разработичками компиляторов я уже не верю. Люди нормально живут в своей парадигме, зачем что-то менять?

В целом поддерживаю ваш комментарий, хотел бы развить в контексте цитаты выше:

А что если отойти в сторону и воспринимать комитет, как политический орган. По сути ISO это прослойка между Государством (заказчиком) и бизнесом (потребителем). Тогда все встает га свои места:

Комитет — это международное техническое бюро по стандартизации технологий. Призван регламентировать с одной стороны, давать техническое обеспечение с другой.

Обожаю пример с ПДД. Мы вынуждены регулировать движение транспортных средств по дорогам общего пользования. Как итог, бизнес производит относительно безопасное современное движение транспортных средств по тем самым дорогам общего пользования.

Все эти правовые, научно-прдпринимательские отношения решаются в таком порядке. Поэтому лаг.

но не мне решать, даст ли предложение о выпуске стандарта каждый год, ускорение имплементации клнечных решений в бизнес конвееры (в поле).

… или как это работает?

Комитет — это международное техническое бюро по стандартизации технологий.

Интересная аналогия, спасибо.

Но, имхо, сравнивать лучше не с ПДД. ПДД -- это ближе к каким-нибудь стандартам MISRA.
А вот ISO-шный стандарт для C++ больше похож на ГОСТы для строительных материалов: типа плиточный клей такой-то, пеноблок такой-то, плита перекрытия такая-то. Т.е., согласованные экспертами спецификации, а уже конкретная продукция, удовлетворяющая этим спецификациям, производится разными заводами стройматериалов.

Только вот получается, что если тебе нужно построить дом, то ориентироваться приходится не на то, что есть в принципе, а лишь на то, что доступно в ближайшем магазине стройматериалов. И если туда чего-то не завезли, то не судьба -- спецификация живет отдельной жизнью, ассортимент в магазине -- своей :(

Тоже не плохой пример, но и комитет не всесильный орган, а лишь техническая экспертная группа.

А вот кто в правительстве следить за соответсвие продукции стандартам — могу только догадываться.

Вот поэтому-то и есть идея о том, что комитет вводит дополнительный статус для предложений: готово к включению в стандарт, но еще не реализовано. И такие фичи в текст стандарта не включаются до тех пор, пока не перейдут в статус "готово к включению в стандарт, реализовано".

Т.о. компенсируется та проблема, что комитет не может повлиять на скорость реализации конкретной фичи в компиляторах. Но зато может формировать стандарт только из тех фич, которые уже реализованы в основных компиляторах.

От того, что какая-то фича будет ждать своей реализации годами нас это не спасет. Но зато мы точно будем понимать, что если есть условный С++32, то он практически весь реализован в свежих версиях компиляторов. А не как сейчас.

Ну и при таком раскладе публикация стандарта раз в год приобретает большой смысл, т.к. если какая-то фича оказалась реализована в большой тройке, то нет смысла ждать больше года, чтобы она стала частью официального стандарта.

Да вот как раз слона проще есть по частям. Всем будет понятнее "естественный" порядок имплементации фич, типа сначала сделайте 26, а потом уже 27 (который частично зависит от 26).

А код на модули переведут ? ;)

C++20 modules support is still experimental and needs to be
enabled with @option{-fmodules} option.

И еще вот такой вопрос: а комитет хоть как-то озадачивается тем, что в реальной жизни есть два C++:

  • описанный в стандарте;

  • доступный обычным разработчикам в конкретных компиляторах.

Причем одно далеко не всегда соответствует второму. И существует серьезный разрыв по времени между включением чего-то в стандарт и появлением этого же хотя бы в большой тройке компиляторов.

Пока что есть ощущение, что комитету, мягко говоря, фиолетово. Мол, мы включим в стандарт некую фичу, а когда это доберется до простых смертных (особенно тех, кто вынужден пользоваться разными компиляторами на разных платформах) -- не наши проблемы.

Я помню каково было ждать, пока нормальная поддержка С++98 в компиляторах появится. А потом поддержка C++11. После чего вот прям благодать настала со стандартами C++14 и C++17. Но вот уже с C++20 опять та же срань :(

PS. Понимаю, что комитет не управляет разработкой компиляторов в Microsoft, Apple или RedHat. Но хотя бы о таком разрыве говорят?

Пока что есть ощущение, что комитету, мягко говоря, фиолетово

А как иначе? Ну вот занимает столько-то времени у вендоров выкатить эту фичу, что комитету прикажете делать?

А как иначе?

Мне думается, что если проблема есть, то:

  • начать можно с того, чтобы хотя бы признать ее официально;

  • после ее официального признания можно будет начать искать способы решения.

Например, можно доработать "train model" по которой ведется развитие стандарта. Скажем, фича N получает статус "одобрена для включения в стандарт". После чего она не включается автоматически в стандарт, а ставится на паузу до тех пор, пока ее драфтовая реализация не появится, например, в gcc+clang+msvc. Когда драфтовая реализация появляется, фича включается в стандарт.

При этом если при реализации фичи обнаруживаются подводные камни, то все это решается без оглядки того, что фича N уже отлита в граните включена в стандарт.

Нет способов решения проблемы вида: "мы можем выкатить эту фичу не меньше чем за N времени" — кроме как выкатив её самому быстрее (для опен сорсных решений), или проспонсировав её форсирование (удачи проспонсировать майкрософт).

Когда драфтовая реализация появляется, фича включается в стандарт.

Что это изменит на практике в вопросе ожидания? Мне, как пользователю, ни тепло, ни холодно от того, в какой момент на бумаге что-то появилось.

Нет способов решения проблемы вида: "мы можем выкатить эту фичу не меньше чем за N времени"

А я и не предлагаю решать эту проблему.

Я предлагаю решать другую: формально включать в стандарт только то, что есть хотя бы в основных компиляторах.

Что это изменит на практике в вопросе ожидания?

Чуть меньше чем все, наверное.

Сейчас вот в стандарте есть std::start_lifetime_as, на практике ее нет.
Ну и что мне с этим делать? Писать какие-то свои заглушки, который будут затем развернуты в актуальный вызов std::start_lifetime_as когда он появится.

А так нет start_lifetime_as в большой тройке, и в стандарте ее нет.

А я и не предлагаю решать эту проблему

Т.е. вы предлагаете просто позаниматься канцелярскими делами. Зачем на это тратить время, правда, не очень понятно.

Чуть меньше чем все, наверное.

Ничего. В обоих случаях я не могу использовать start_lifetime_as . А когда она появится, то в обоих случаях я смогу её использовать в один момент времени.

Т.е. вы предлагаете просто позаниматься канцелярскими делами.

Во-первых, я ничего не предлагаю. Всего лишь интересуюсь рассматривают ли в комитете сложившуюся ситуацию как проблему или нет.

Во-вторых, не понимаю, откуда вы сделали такой вывод. Сейчас судьба пропозала такова: пропозал вносится, над ним работают, затем его признают готовым к включению, после чего он входит в стандарт и, если нужно, далее вносятся правки.

Можно сделать так, что когда пропозал объявляют готовым к принятию в стандарт, то он не вносится в стандарт сразу. А дожидается пока его реализуют. Только после этого его текст вновится в стандарт.

Дополнительный плюс здесь в том, что если в процессе реализации обнаруживаются подводные камни (вот как в случае с trivial relocatable), то не нужно ничего из стандарта отзывать или вносить в стандарт корректирующие правки.

В обоих случаях я не могу использовать start_lifetime_as

Тогда у меня нет ответа на вопрос: зачем иметь в стандарте C++23 фичу, которой нельзя пользоваться на практике в конце 2025-го года?

Меня лично, за 30 лет с C++, эта ситуация очень забодала. Не так конечно, как необходимость использовать CMake, но все-таки. В 1990-е еще было понятно ради чего ждать, типа первый стандарт, в мире C++ ничего подобного еще не было. Но с момента принятия первого стандарта уже 27 лет прошло. А мы как будто бы ничему не учимся.

зачем иметь в стандарте C++23 фичу, которой нельзя пользоваться на практике в конце 2025-го года?

Вам от этого ни тепло, ни холодно, зачем этим вопросом вообще задаваться? Если фичу обозначили как "надо" в N году, а сделали в N+3, то вы сможете ей пользоваться только в N+3 году, независимо от того, внесли ли её в стандарт в году N, или в году N+3.

Вам от этого ни тепло, ни холодно, зачем этим вопросом вообще задаваться?

Вот это сейчас странный заход, ейбоху.

Возьмем std::launder. До C++17 мы тупо сажали в код UB. После C++17 делать какие-то вещи без std::launder -- это опять же сажать в код UB. Но тут как бы есть джентельменская договоренность -- компиляторщики не эксплуатируют этот UB пока мы в предыдущих стандартах. Но если мы в C++17 (20, 23), но не используем std::launder, то сами себе злобные буратины.

Аналогично с start_lifetime_as. Без этого, если мы выставили С++23 как стандарт, мы не имеем права делать какие-то вещи, ибо UB. Значит нужно использовать start_lifetime_as. А его нет. Вот тупо нет. Ключик -std=c++23 есть, часть фич из C++23 есть, а нужного мне нет.

Аналогично можно и с [[no_unique_address]] ситуацию вспомнить. Как бы в стандарте он есть и давно. А вот в компиляторах -- как повезет.

Повторюсь: тут я не понимаю смысла происходящего. В стандарте есть фича, у меня в проекте включен стандарт, но этой фичи нет.

Тогда зачем мне подобный стандарт, если все равно приходится смотреть на фактическое наличие в компиляторе? Зачем включать в стандарт то, что затем по 3 года не может стать доступным для пользователя?

Плохо здесь то, что вот нужен мне start_lifetime_as, а его нет в наличии. Я наговнякую с UB и этот говнокод затем будет жить годами, потому что про него все забудут. А в какой-то момент комплятор начнет эксплуатировать данный UB и придется кому-то искать что и почему. Хотя, если я сейчас в рамках С++23 код пишу, то почему не имею возможности использовать то, что в стандарте описано?

Какая разница НА ПРАКТИКЕ, вы можете ответить? Вот было бы как вы хотите, был бы у вас не -std=c++23 без start_lifetime, а был бы -std=c++2x_ver_26_05_2025 без start_lifetime. Суть-то не изменилась: start_lifetime всё равно нет.

В стандарте есть фича, у меня в проекте включен стандарт

Так это вопрос к вендору. Ответственный вендор назовёт c++2a\b\c\d или c++latest, намекая, что стандарт полностью не поддерживается.

Я наговнякую с UB

Ваши действия — ваша ответственность, не нужно её перекладывать на комитет или вендора.

Какая разница НА ПРАКТИКЕ, вы можете ответить?

На какой практике?

Я вам вот о чем говорю: в стандарте фича есть, в комиляторах ее нет. Это продолжается не с одной фичей и не один год. Вопрос к комитету: комитет считает это нормальным или нет?

Так это вопрос к вендору.

Тут можно посмотреть с точки зрения пользователя: мне без разницы что есть отдельно комитет, отдельно вендоры, мне код писать нужно. Для этого мне нужна фича, которая в стандарте есть, а в компиляторах нет. И мне, как пользователю, хочется посоветовать комитету: ребяты, а могли бы вы построить свою работу так, чтобы в стандарт входило только то, что в компиляторах уже реализовано?

Нет? Точно нет? Точно точно?

Ну раз точно, тогда продолжим жрать кактус.

Ваши действия — ваша ответственность, не нужно её перекладывать на комитет или вендора.

Прекрасно. Есть проект, который уже в рамках C++23.
В какой-то части проекта мне нужно написать что-то вроде:

const std::byte * data_fragment = ...;
const std::size_t payload_offset = calculate_payload_offset(data_fragment);
const auto * payload = std::start_lifetime_as<const data_payload *>(
  data_fragment + payload_offset); 

В рамках C++23 получение указателя на data_payload без start_lifetime_as -- это UB, насколько мне известно.

Вопрос: как мне быть в этой ситуации?

На какой практике?

Это когда я открыл IDE и пытаюсь написать std::start_lifetime_as. Если её нет, то её нет, и от того, что в параметрах компилятора написано не -std=c++23, а -std=c++2x_27_11_2025 мне ни тепло, ни холодно.

И мне, как пользователю, хочется посоветовать комитету: ребяты, а могли бы вы построить свою работу так, чтобы в стандарт входило только то, что в компиляторах уже реализовано?

И сколько ждать нужно? Пока все компиляторы не напишут?

Вопрос: как мне быть в этой ситуации?

Также как вы были прошлые 30 лет? Или вам первый раз понадобилось превратить набор байт в какую-то структурку, а тут подлый комитет палки в колёса вставил?

А вообще, p0593 существует. Так что пользуйтесь pre-c++23 вариантомstd::launder(static_cast<T*>(std::memmove(p, p, sizeof(T))));

Это когда я открыл IDE и пытаюсь написать std::start_lifetime_as. Если её нет, то её нет, и от того, что в параметрах компилятора написано не -std=c++23, а -std=c++2x_27_11_2025 мне ни тепло, ни холодно.

Вы, видимо, упорно игнорируете то, что я вам пишу про пример с start_lifetime_as. Ну ОК, кроме вашего упрямства это больше ничего не демонстрирует.

И сколько ждать нужно?

Сколько нужно. Люди вот годами ждут сеть и экзекуторов в стандарте. Ждут и ждут, ждут и ждут.

А потом будут ждать и ждать появления в компиляторах.

Так что ничего принципиально не изменится: ждать придется столько, сколько нужно, а сколько нужно никто не знает.

Пока все компиляторы не напишут?

В идеале. Но меня бы лично устроила большая тройка (особенно с учетом того, что часть ранее независимых компиляторов перешла на LLVM/clang).

Так что пользуйтесь pre-c++23 вариантом std::launder(static_cast<T*>(std::memmove(p, p, sizeof(T))));

Да я-то сколько угодно разных костылей могу в код напихать. При этом у меня нет уверенности в том, что использование std::launder здесь корректно начинает лайфтайм для объекта (и начинает ли вообще).

Вопрос в другом: считает ли комитет такую ситацию нормальной?

PS. Ну и есть более сложные случаи, вроде [[no_unique_address]], которые так просто не объедешь.

После чего вот прям благодать настала со стандартами C++14 и C++17. Но вот уже с C++20 опять та же

С C++20 основная засада - модули. Остальное всё уже реализовано, но модули - очень большая и многогранная фича, требующая работы над множеством частей C++ (форнтенд и мидленд компилятора, линкеры, системы сборки, библиотеки, ...)

В С++23 и C++26 нет таких "монстров", так что должно всё гладко идти и вендоры быстро наверстают отставание

С C++20 основная засада - модули

Если я правильно запомнил тезисы твоего выступления на C++ Zero Cost Conf про модули ,то там основная засада, это макросы препроцессора.

Хотелось бы услышать твое мнение насчет этого предложения, которое должно решать проблемы модулей с макросами и сохраняет обратную совместимость со старым кодом.

Международный комитет выступил против подобной идеи https://github.com/cplusplus/papers/issues/2316

Если хочется продолжить работу - нужна новая, более внушительная, мотивация

Это совершенно другое предложение, которое наоборот запрещает экспорт макросов из модулей и добавляет обработку имен макросов в С++ модулях на уровне AST, а не только во время работы препроцесоора.

Идея https://github.com/cpp-ru/ideas/issues/622 предлагает экспортировать макросы из global module fragment для именованных модулей. https://github.com/cplusplus/papers/issues/2316 предлагал то же самое

Та часть вашего предложениея, что

#define MACRO_LOCAL macro_local

import mod; // В модуле mod видны оба макроса  MACRO_GLOBAL и MACRO_LOCAL

никак не сможет работать с модулями. Именованный модуль уже "запечён", и в него ничего больше не прилетает. Такой модуль - это практически иммутабельный бинарный блоб. Что-то схожее предлагалось в https://github.com/cplusplus/papers/issues/2316 и комитет был против

Данный пример не принципиальный и не является ключевым. Ведь новое поведение может быть каким угодно, и раз модуль "уже "запечён", и в него ничего больше не прилетает. ", тогда пусть локальные макросы модуля будут доступны только внутри компилируемого модуля, а в импортируемых модулях недоступны.

Поправил описание предложения

Что-то схожее предлагалось в https://github.com/cplusplus/papers/issues/2316 и комитет был против

Это совершенно другое предложение, которое наоборот запрещает экспорт макросов из модулей и добавляет обработку имен макросов в С++ модулях на уровне AST, а не только во время работы препроцесоора.

Приведите пожалуйста примеры, какой именно новый функционал получаем, с данным предложением. Да, заставить макросы работать по правилам C++ - это приятно, но слишком много нюансов и проблем возникает, пока кажется что овчинка не стоит выделки

В данном случае никакой новый функционал не добавляется и основная задача предложения - это не сломать старое поведение мароксов в легаси коде (с их обработкой только в препроцессоре)

Но так как макросы действительно ломают логику в С++ модулях, то формально макросы остаются, (чтобы не получить негатив от приверженцев старого С++), но их поведение в модулях меняется, так как добавляется дополнительный анализ на уровне AST. Фактически это плавный переход от макросов препроцессора к будущей рефлексии, т.к. с помощью последней можно сделать примерно тоже самое.

но слишком много нюансов и проблем возникает, пока кажется что овчинка не стоит выделки

Я могу сделать пример реализации этой фичи с помощью clang плагина, чтобы была возможность проверить предложенное поведение на реальном коде, но вряд ли смогу понять её применимость для С++ модулей, так как не знаю всех их тонкостей и нюансов.

В данном случае никакой новый функционал не добавляется и основная задача предложения - это не сломать старое поведение мароксов в легаси коде (с их обработкой только в препроцессоре)

Но ведь макросы и так можно использовать в именованных модулях в global module fragment и они прорастают ниже в module unit, и за его пределы не экспортируются.

Так зачем делать работу, по обучению AST в макросы?

Для того, чтобы с помощью макросов препроцессора нельзя было переопределять интерфейс модуля (изменять имена экспортируемых классов и функций).

А почему почему вы хотите это запрещать? Например многие проекты используют макрос, чтобы задать namespace и inline namespace с версией. С вашим предложением этот функционал перестанет работать

Пускай задают, на внутренне поведение это никак не влияет.

Ограничения нужны только для публичного интерфейса модуля, чтобы его нельзя было переопределить во время компиляции (чтобы исключить ошибки в интерфейсе модуля из-за макросов во время компиляции)

Именно на публичный интерфейс и влияет макрос для namespace, так что сломается :(

Но ведь именно эту проблему ты и озвучивал в своем докладе (потенциальная зависимость интерфейса модуля от макросов времени компиляции), но если этой проблемы не существует, тогда мое предложение действительно не имеет смысла.

Если же такая проблема все же присутствует, тогда её можно решить добавлением анализа имен макросов после построения AST, но вот в каких местах это нужно делать, я со 100% точностью сказать не смогу.

Если ты считаешь, что раскрытие макросов в namespace допускаются, пусть будет так. Как я уже сказал, я не знаю всех тонкостей использования модулей и не вижу смысла спросить со специалистом.

встречи ISO C++ на Гавайях

Как там погода, на Гавайах?
Почему статья без фотографий? Стоило ли собираться на Гавайях, если нет классных фоток?

Какой вообще смысл в таких тусовках? Что там происходит такого, чего нельзя решить с помощью телеконференций и дистанционного голосования?

Как там погода, на Гавайах?

Не в курсе, я удалённо участвовал :)

Но не удивлюсь, если офлайн участники тоже не знают какая там погода - обычно времени на осмотр окресностей нет, график очень плотный, а в больших аудиториях с окнами зачастую напряжёнка

Какой вообще смысл в таких тусовках?

Основной смысл - общий сбор, точка синхронизации и формального голосования. Онлайн тоже есть, но встреча работает эффективнее

На таких встречах тайно договариваются, как сделать чтобы язык был максимально сложным. В стандарте С++36, добавят обязательное чтение мантры для успещного запуска программы, чтобы LLM не смогла писать код вместо человека. Смыслом жизни станет изучение и трактовка стандартов. Подготовку специалистов перенесут в закрытые монастыри.

В P1789 std::integer_sequence обзавёлся методами, позволяющими использовать его в structured binding и template for:

И я вдруг понял, что этого всю жизнь не хватало.

Но еще жизнь надо будет подождать, пока я на 26 стандарт перейду.

В частности, на этом заседании не дошли руки до P3725, который делает надёжный и безопасный std::ranges::filter, не подверженный проездам по памяти и Segmentation Fault в примерах наподобие:

господи, да что не так с этим языком. почему нельзя было сделать, чтобы всё работало нормально изначально. сколько те рэнжи пилили, а косая кривулина всё равно оказалась в стандартной библиотеке да ещё и в одной из самых востребованных частей и теперь изобретают другую такую же штуку, но другую, которая будет подтирать кособокость первой.

Отдельно вопрос - а не думал ли кто-нибудь сделать альтернативные API на опционалах по аналогии ржавых?

альтернативные API на опционалах

Вроде бы уже всё есть. Можете пожалуйста привести пару примеров, чего не хватает?

В std примерно нигде не используются опционалы, насколько мне известно. Везде итераторы и сентинелы в лучшем случае.

Любой из find API (хоть на строках, хоть на рэнжах) возвращает либо индекс (по старой сишной традиции -1 для "не найдено"), либо итератор и я пока не видел чтобы хоть кто-то вернул std::optional или std::expected. Хотя казалось бы логичным писать что-то вроде

if (auto result = haystack.find(needle)) {}

В API контейнеров есть места, где возвращаются пары, где одно из значений - успех выполнения команды - std::unoredered_map<K,V>::insert(), например. Кажется адекватное применение для опционалов. Штуки типа std::from_chars - самое оно для expected. .at тоже нигде не возвращает опционалов, то есть нет ни одного такого noexcept аксессора - будь-то контейнер, span или строка.

По-хорошему иметь дубликат всех APi которые кидают исключения в виде опциональных вариантов.

Отдельно наверное стоит спросить за перегрузки с автоматическим приведением контейнеров к range в алгоритмах, чтобы тот же find писать std::find(container, predicate), а не писать границы каждый раз ну и соотвественно иметь возможность делать что-нибудь а ля

auto range = container
  |filter([]{...})
  |transform([]{...});
std::find(range, predicate);

Ествественно одним только find не ограничиваться, но и прочие подходящие алгоритмы тоже.

Отдельно - API для взаимодействия итераторов - chain, zip, cycle и прочие.

Кажется адекватное применение для опционалов.

Каким образом? Там же итератор возвращается всегда, независимо от того, был уже этот элемент в контейнере или нет, в этом весь смысл такого API.

По аналогии с ржавым. А обновление делать через какой-нибудь insert_or_update(). Собственно. поэтому вопрос про альтернативные API, типа как flux сделал, оставив некоторый слой совместимости с UB из std, ибо воткнуть их в текущую реализацию без горожения ещё большего ахтунга кажется нереально.

Сейчас очень частая задача вида "если элемента с таким-то ключом еще нет в мапе, то вставить начальное значение, если он есть - то инкрементировать его на N" благодаря текущему API решается за один лукап. Продемонстрируйте, пожалуйста, как такая задача будет решаться за один лукап "по аналогии со ржавым" или "через какой-нибудь insert_or_update()", а то лично мне например непонятно, в чем состоит идея и как эта идея что-то реально улучшит, за исключением "перехода на опционалы ради перехода на опционалы".

то инкрементировать его на N"

В Rust такая задача решается как-то так:

map
.entry(key)
.and_modify(|v| *v += N)
.or_insert(value);

entry соотвественно вернёт обёртку над значением внутри контейнера, которое вы вольны обновить как вам угодно, если оно существовало. Иначе вставляете ваше желаемое значение.

В С++ вы всё это вытворяете ручками.

auto [it, ok] = map.insert({key, value});
if (!ok) {
  it->second += N;
}
// ну раз мы итератор, то давай ещё и пошагаем
it++; // при желании можем выстрелить себе в ногу
      // за единственный же лукап

Минусы

  • метапотроха мапы становятся чуть более публичными в сравнении с голыми итераторами и чуть менее универсальными

  • нельзя переключиться на следующие элементы в контейнере (есть юзкейс?)

  • контейнеры с++ для такого надо будет переделывать

Плюсы:

  • инкапсуляция намерений - обновление и вставка две разные операции, понятнее, что хотел сказать автор, да ещё и из коробки

  • избавляемся от потенциальных UB - ни .end()++ ни *.end() исполнить не получится.

Ну а основная цель перехода на опционалы - переход к noexcept и локализация обработки ошибок ближе к собственно местам потенциальных ошибок, а не где-то на 10 уровней выше по стеку со всеми проблемами разворачивания стека.

В Rust такая задача решается как-то так:

А вы уверены, что решается именно эта задача? Я вот сейчас не поленился, написал тест с вырожденной хеш-функцией, намеренно создающей коллизии. И что-то как только я комментирую часть .or_insert(i), так сразу время выполнения примерно вдвое падает. Ну прямо очень похоже на отдельный лукап на вставке. Да и с чисто технической стороны вопроса, из описания всех этих or_insert следует, что они выполняют полноценную операцию вставки, включая лукап. Иначе согласно этому API бы приходилось сначала всегда вставлять какой-то элемент в букет, если элемента с соответствующим ключом нет, а если or_insert не вызван, то приходилось бы его удалять при уничтожении экземпляра Entry, верно? А если вставляемый экземпляр невозможно создать со значениями "по умолчанию", как быть? Вопросы, вопросы...

P.S. Есть конечно вариант не вставлять "пустое" значение, а просто найти букет и держать его, но тогда получается, что ты не можешь найти Entry, потом что-нибудь сделать с map (скажем, вставить что-то или удалить), а потом сделать что-то с сохраненной Entry. В расте эта проблема "решается" тем что Entry "одалживает" map в свое полное распоряжение, и ты ничего не сможешь с этим map сделать, пока экземпляр Entry не уничтожится. Ну, тоже такое себе в приложении к C++.

The hash table implementation is a Rust port of Google’s SwissTable.

я не знаю как конкретно этот swiss table резолвит коллизии. И не понимаю почему or_insert триггерит пессимизацию производительности в дебаге учитывая, что там обычный матч по собственному состоянию.

то приходилось бы его удалять при уничтожении экземпляра

да, каждая из API ожидаемо делает то что вы предполагаете. Entry не делает грязи как плюсовые квадратные скобки.

А если вставляемый экземпляр невозможно создать со значениями "по умолчанию", как быть?

То вы его самостоятельно конструируете и отдаёте в функцию вставки. В Rust по-умолчанию везде перемещение, а не копирование так что оно практически in place конструируется.

map
.entry(key)
.or_insert(NonDefaultConstructible::new(/*args*/))

Есть конечно вариант не вставлять "пустое" значение, а просто найти букет и держать его

это уже всё детали реализации, которые я не читал. В гугловых тоже не смотрел. Можете попробовать сравнить cpp с rust и посмотреть будет ли там деградация на коллизиях. Abseil можно подключить на godbolt.

И не понимаю почему or_insert триггерит пессимизацию производительности в дебаге учитывая, что там обычный матч по собственному состоянию.

Ну так-то в данном конкретном месте матч, да, но потом через десятые руки в hashbrown::hash_map вызывается вот такое:

impl<'a, T, A> VacantEntry<'a, T, A>
where
    A: Allocator,
{
    pub fn insert(self, value: T) -> OccupiedEntry<'a, T, A> {
        let bucket = unsafe {
            self.table
                .raw
                .insert_tagged_at_index(self.tag, self.index, value)
        };
        OccupiedEntry {
            bucket,
            table: self.table,
        }
    }
}

Т.е. VacantEntry запоминает внутри себя что-то типа индекса букета и вставляет там значение в этот букет. На беглый взгляд вообще выглядит не так плохо с точки зрения производительности, но с точки зрения переложения этого механизма на C++ выглядит не очень.

Можете попробовать сравнить cpp с rust и посмотреть будет ли там деградация на коллизиях.

В текущем C++ API деградации на коллизиях просто неоткуда взяться, так как после единственного лукапа при insert мы сразу получаем итератор, указывающий на конкретную прямо KV-пару, и все на этом, дальше работа идет просто с этой KV-парой напрямую. Можно вообще взять на нее ссылку сразу, никто не мешает. Там все ясно и понятно. У раста же многое зависит от качества реализации вот этой прослойки всей, нужно с бутылкой засесть и потеть, если хочешь разобраться, не факт что какие-нибудь умельцы чего-нибудь не пессимизируют потом... Ну и конечно тот факт что Entry пожирает всю мапу до конца своего лайфтайма, тоже мягко говоря, не очень удобно.

Так вы сравниваете производительность разных имплементаций. Стандартный контейнер раньше при коллизиях вырождался в список со длинющим линейным лукапо со всеми вытекающими. Ситуацию вроде несколько улучшили, но всё равно просадка на коллизиях имеет место быть и тут не сильно принципиально, что он единственный. Гугловая табличка из abseil должна делать примерно то же самое, что и ржавая и оба делают SIMD-оптимизации лукапов, так что оно даже если с двойным лукапом должно получится быстрее чем стандартный лукап в std::umap/std::uset. Ну, а считать производительность на вырожденных случаях в дебаге несколько странное занятие.

Ну, а считать производительность на вырожденных случаях в дебаге несколько странное занятие.

Меня главным образом интересовало, сколько лукапов делает реализация через эти Entry в расте, и было две альтернативы - сидеть с бутылкой и разбирать внутренности Entry или по-быстрому попробовать грубо оценить через тайминги на вырожденном случае. Ну хотя внутренности все равно пришлось разбирать.

это апи в крабовый язык добавлено исключительно потому что по другому невыразимо в так называемом safe подмножестве. То есть другими словами это костыль с оверхедом и абсолютно нечитаемый.

И вы предлагаете костыль перетащить в язык, где всё сделано логично и правильно

костыль с оверхедом и абсолютно нечитаемый.

вот тут я бы попросил пруфов. и за оверхэд и за нечитаемость.

И вы предлагаете костыль перетащить в язык

Я ничего не предлагаю. Я хочу, чтобы язык развивался для людей и не позволял отстреливать ногу при использование стандартной библиотеки.

 где всё сделано логично и правильно

видимо поэтому глупые людишки переизобретают стандартные контейнеры во всяких Abseil, Eastl и Beman. То ли дело комитет, который логично сначала депрекейтит вещи, потом следом раздепрекейчивает их в следующем стандарте и превращает простые и чистые пропозалы в нагромождение спецсимволов, потому что проще поменять стандарт, чем компилятор (см. первые пропозалы по pattern matching и как оно выглядит сегодня). Ну и проблема option<T&> конечно же возникла не из-за костыля, а идиоматическая несовместимости. Казалось бы никто и подумать не могу, что люди попытаются провернуть такой трюк.

То есть другими словами это костыль с оверхедом и абсолютно нечитаемый.

добавлю что эти коллбэки ещё и значительно усложняют дебаггинг

С одной стороны да. std::ranges позволяют написать вместо

auto it = std::find(long_container_name.begin(), long_container_name.end(), element_to_find);  
if (it != long_container_name.end()) { ... }

написать

auto it = std::ranges::find(long_container_name, element_to_find);  
if (it != long_container_name.end()) { ... }

спасибо и на этом. Но удобная вариация с std::optional, сделанная для людей позволила бы писать так:

auto it = std::ranges::try_find(long_container_name, element_to_find);  
if (it) { ... }

А если оно будет сразу в контейнере, то так:

auto it = long_container_name.try_find(element_to_find);  
if (it) { ... }

и это никак не ломает существующий код.

it может быть как std::optional от объекта, так и от итератора - тут уж не знаю как правильнее. Но это позволит не писать название вектора три! раза, чтобы выполнить самую базовую операцию.

Ну я же не отрицаю возврат итераторов. Просто он удобен не во всех сценариях, поэтому и хотелось бы иметь ряд удобных встроенных функций с возвратом optional поверх API на итераторах.

"Trivial relocation в С++26 не будет" - и слава богу, прогнули Bloomberg. Этот уродливый trivial_relocatable_if_eligeable какой то отдельный сорт булшита, кому пришла идея даже рассматривать такое.

Напомнило приснопамятную булевскую переменную unable_to_already_enable_or_disable )

Полировка идёт, а больные места по-прежнему на паузе. Вроде движемся, но как-то очень аккуратно и без амбиций

А какие именно больные места?

Сеть осталась, асинхронный ио

Серьёзно? Это хороший ответ? Блин, там аргумент от школьника на перемене). Какойто ноунейм (пусть и std контрибьютор) говорит сети нет потому что средний мейнтейнер не осиляет, зшбсь дискуссия)

Этот, как Вы выразились, ноунейм имеет имя: Stephan T. Lavavej. Он единственный мейнтейнер стандартной библиотеки от Microsoft. И я бы рекомендовал прислушаться к тому, что говорит этот человек, когда речь идёт о стандартной библиотеке. Он знает, о чём говорит.

О чём свидетельствует, кстати, скорость реализации std::format, std::ranges и прочих «простых» библиотек. Лично я уже давно пришёл к выводу, что C++ не в состоянии вывезти сложные библиотеки через стандарт, потому что минимум 3 реализации, которые, как я понимаю, друг у друга брать не могут, это слишком много.

А, это Лававей) не смотрел в профиль подробно. Но сути не меняет, даже выглядит ещё страннее. В мире где любой мейнстримный язык по дефолту может даже в HTTP (а не просто в сокет) сопротивлятся внедрению сети в std странно. И вдвойне нехорошо что даже авторитеты, влияющие на комьюнити высказываются в таком ключе. Втройне обиднее что аргумент авторитета звучит как - "ментейнеров нет", хотя причём тут реализация? Внеси в стандарт а там уж как нибудь и реализация подоспеет, format, модули и корутины не дадут соврать. "Вчетверне" странно что linalg (вот уж без чего никак) взяли а сети всё нет, хотя asio уже отполирован сто лет как.

Я с Вами по сути согласен, я был тоже очень воодушевлён, когда много лет назад Саттер рисовал красивые картины светлого будущего, где в стандарте C++ будет много библиотек и потом как заживём... Но затем я увидел, с какой скоростью происходит реализация библиотек в MSVC/gcc/clang, и мой оптимизм полностью сошёл на нет. Вплоть до того, что я предпочитаю {fmt} std::format, потому что так мне нужно бодаться с одной библиотекой, вместо трёх, если что-то пойдёт не так.

Возможно ли, что ситуация изменится? Да, но для этого нужны хорошие вливания в MSVC/gcc/clang, а после фортеля от White House про «безопасные языки» ждать этого не приходится. По крайней мере от США. Так что фантазировать можно сколько угодно, но реальность на данный момент STL описал очень хорошо.

Но хорошо, что необходимости тащить библиотеки в стандарт всё-таки нет, т. к. туда зачастую хотят тащить уже имеющиеся, проверенные временем решения, которые можно использовать уже сейчас.

Вроде хотели что-то стандартное сделать для управления/объявления/обнаружения зависимостей. Есть новости?

UFO landed and left these words here

Можно предположить, что после появления рефлексии кому нужны properties смогут воплотить свои хотелки в жизнь самостоятельно.

UFO landed and left these words here

Я к тому, что properties -- это одна из самых спорных штук из тех, что хотелок, которые люди высказывали. На моей памяти любители properties говорят об этом с середины 1990-х, более того, ЕМНИП, Borland и Microsoft добавляли их поддержку в свои С++компиляторы в то время в виде нестандартных расширений языка.

Прошло 30 лет, никто от отсутствия properties не умер. А кто-то (вроде меня) и вообще не хотел бы их в языке видеть. Так что вероятность их добавления, имхо, крайне низкая.

Зато через рефлексию все любители этих самых properties смогут обеспечить себе свое личное щасте с большой буквы "Ща" ;)

UFO landed and left these words here

Но зачем усложнять работу компиляторостроителям ради фичи, которую не будут использовать, скажем, 90% пользователей языка?

У Страуструпа несколько лет назад было хорошее послание к комитету под названием "Вспомните Vasa": https://www.stroustrup.com/P0977-remember-the-vasa.pdf

UFO landed and left these words here

Откуда вообще такая статистика? 90%, а может 89%?

Это не статистика, вы не обратили внимания на слово "скажем" в моем предложении.

Но если вы хотите убедить комитет в важности такой фичи, как properties, то вы можете как-то собирать такую статистику и продемонстрировать.

Так же после появления рефлексии вы можете написать прототип и на реальных примерах показать как хорошо решаются те или иные проблемы.

Кто-то помер там от отсутствия фич языка, а кто-то не помер?

Сам факт того, что за последние 30 лет огромное количество софта было написано на C++ без properties доказывает, что это не критичная штука.

При этом те же самые 30 лет показывают, что по каким-то темам накапливается критическая масса пожеланий для внедрения новых фич (variadic templates, lambdas, if constexpr, concepts, compile-time reflection, ...). Т.е. по этим направлением выгода от новых фич достаточно очевидна.

По поводу properties большие сомнения. Но вы можете их попробовать развееть.

Может попытаемся вести адекватный диалог?

Да я как бы уже. Но адекватные не означает, что здесь будут озвучиваться вещи которые удовлетворят вас.

UFO landed and left these words here

а, ну слово "скажем" все меняет конечно

Вы не поверите...

UFO landed and left these words here
UFO landed and left these words here

Любезный, я практически никогда не ставлю минусы на Хабре. За все время присутствия здесь минусов от меня для статей/комментариев наберется всего с десяток. А минусов в карму не было вообще никогда.

В этом обсуждении я ни одного минуса никому не поставил.

Но пруфов не будет, придется поверить на слово.

UFO landed and left these words here

Страуструп очень заботился о том, чтобы C++ был однозначным языком.

А теперь… может быть, я чего-то не понимаю, но объясните мне, пожалуйста — как, не имея кода библиотечной функции, я должен понять, используется ли внутри неё move-синтаксис, от наличия (или отсутствия) которого может зависеть время жизни возвращаемого этой функцией объекта?..

Подробности:

Мы здесь рассматриваем синтаксис возвращаемого функцией значения. Изначально это мог быть сам объект, простая не константная ссылка, либо указатель. Различить при этом объект и не константную ссылку возможности не было. Для оптимизации Страуструпу пришлось ввести ключевое слово const, которое привели к const-хеллу в языке, для решения которого он предлагал не очень удачное решение с typedef'ами.

Поэтому в итоге сложилась достаточно понятная система, в которой возврат не константных ссылок просто считался плохой практикой программирования. И при её неприменении вся работало однозначно: если функция возвращала что-то по значению, то вы просто автоматически предполагали, что это временный объект (и например, могли использовать константную ссылку для его сохранения), не получая абсолютно никаких проблем.

А если функция нуждалась уже в изменении получаемого снаружи объекта, то просто использовался имеющий несовместимый (и сразу заметный) синтаксис не константный указатель — встретив который, можно было с почти 100% уверенностью предполагать (исключая разве что неправильное архитектурное проектирование или чужие ошибки), что функция либо получает его же снаружи в параметрах, либо создаёт внутри себя (и тогда вам надо контролировать утечки памяти).

Более того — хотя все современные программисты уверяют меня, что это сейчас не так, но я почему-то уверенно помню, что конструкция:

// первый пример
namespace OuterSpace
{
OuterFunc( InnerFunc() );
}

— раньше* (см.примечание внизу текста) сохраняла возвращаемый временный объект функции InnerFunc() не только на весь вызов OuterFunc(), но и до вообще аж конца области видимости OuterSpace. Я не знаю достоверно, откуда это взялось (возможно, просто по той причине, что так работали компиляторы той эпохи). Но чёрт возьми, это было удобно!

А вот в современном языке это уже не так — и он заставляет меня писать:

// второй пример
namespace OuterSpace
{
auto TempObject = InnerFunc(); // это лишняя строчка, которая загрязняет читаемость кода!
OuterFunc( TempObject );
}

— и в результате вышеприведённые два примера становятся неравнозначными!

Потому что, если написать, как в первом примере выше, то можно легко напороться на ситуацию, когда неименованный временный TempObject из первого примера уничтожится, не доходя даже вовнутрь OuterFunc, т.к. его областью видимости почему-то являются круглые скобки, а не фигурные!

Итог:

— Какого чёрта, Карл? Зачем мне весь этот синтаксический мусор из новых спецификаций, если язык поломали в самОй его основе?..

— А теперь подумайте, что возвращаемое значение может быть ещё и лямбдой! Я им что, компилятор, такие вещи в голове прикидывать?!..

— Я хочу сказать, что помимо спецификации C++, в мире написано огромное количество литературы, разъясняющей те или иные тонкие моменты. И — возможно! — несмотря на попытки сохранить обратную совместимость, всё-равно произошёл неявный ДРЕЙФ ЯЗЫКА относительно этих описаний (которые априори недоступны для изменений никакому комитету по стандартизации).

  • прим: "раньше" — это что-нибудь вроде Watcom C++11 под DOS, а не что-то более новое.

p.s. в качестве послесловия хочу добавить, что в то время, когда я изучал C++ в первый раз, ещё не существовало его полного описания (не текстового в книгах, а формально-алгоритмического, для компиляторов). Такое машинное описание было разработано позже (и об этом даже была новость несколько десятилетий назад). Поэтому производители ранних компиляторов принимали ситуативные решения сами — и некоторые из этих решений очевидно оказались удобнее того, что разработал комитет в более поздних спецификациях C++.

Потому что, если написать, как в первом примере выше, то можно легко напороться на ситуацию, когда неименованный временный TempObject из первого примера уничтожится, не доходя даже вовнутрь OuterFunc, т.к. его областью видимости почему-то являются круглые скобки, а не фигурные!

C++ так не работает, в данном примере временные объекты будут жить до окончания вызова функции OuterFunc.

Или вы имеете в виду, что OuterFunc возвращает ссылку на локальную для OuterFunc переменную. В этом случае у меня для вас плохие новости - этот код всегда был UB, при том и в чистом C вы скорее всего получите проезд по стеку.

А точно не до конца блока, в котором OuterFunc вызвана?

И однозначно ли это определено?

Надо будет сделать деструктор и глянуть.

1.да. Сразу после возвращения из outer объект удаляется. Даже на старом gcc 4.8

Как человек, у которого первая любовь это С++, и рботаю я на нем уже лет 15, советую молодым изучать питон, С, java, go, rust на худой конец, но не С++.

То что делают эти ребята в комитетах, это не про комфорт и заботу. Просто посмотрите другие ЯП и сами сравните, на чем вам проще решить вашу задачу, и сколько стоит вход для новых, сколько стоит поддержка, сколько возможностей выстрелить себе в ногу и тп и тд :)

А подскажите, как сделать лучше? Что упростить?

Ну, достаточно посмотреть любую статью PVS здесь - что можно улучшить, чтобы трудно было сделать такие ошибки. Или Cpp Core Guidelines - которые предлагаю рецепты, чтобы Вы не выстрелили себе в ногу, т.к. наш инструмент (С++) это сделает легко и даже не моргнет. Еще есть MISRA C++, clang-tidy и тп, можно посмотреть что они проверяют. Их много и их наличие говорит о тех самых "костылях" в С++ (которые мы называем особенностями).

Память - наша гибкость с одной стороны и ахилесова пята с другой. Обратите внимание, на С++ написано много кода которому не нужна такая гибкость и эффективность, это сейчас достигается 100500 опциями ворнингов и -Werror. Да, есть санитайзеры, clang-tidy, статические и ко, но почему они сбоку, а не в ЯП и компиляторе ?

Жили были, оператор "<", "==", ">", ..., а потом бац и добавили spaceship operator - "<=>", ну окей, но, почему оператор в ЯП, а значения в STL ? Опять же, видны проблемы с модульностью. Да и еще прямо в глобальный неймспейс STL добавили (как и многое другое), такими темпами, там будет мусорка, не ?

Просто такое ощущение, что у С++ нет мейнтейнера, а есть куча комитетов, где каждый тащит свое и как хочет, вот и получается, кто заплатил и зашел, то и затащил, вот и результат - комбайн, со структурными проблемами. Все это еще приправляется "мы никогда не откажемся от обратной совместимости" и получается китайский комбайн.

Это вот по [С++11 - С++23].

По экосистеме: посмотрите на pip, почему у нас такого нет ? Почему до сих пор у нас 100500 систем сборки (Make, CMake, ...), 100500 каналов распространения либ (гитхаб, системные менеджеры пакетов, сайты, ... ? Я бы рекомендовал комитету обратить на это внимание, ведь это задача стандартизации и портит мнение о ЯП. Потом воспроизводимость сборки, которой также нет.

Это так, если сумбурно и по памяти :)

По экосистеме: посмотрите на pip, почему у нас такого нет ? Почему до сих пор у нас 100500 систем сборки (Make, CMake, ...), 100500 каналов распространения либ (гитхаб, системные менеджеры пакетов, сайты, ... ?

А у вас у самого есть версия почему так?

Потому что комитету было пофиг на все, если коротко.

Понятно, что интерпретируемый язык это другой мир, в отличии от компайл языка, и в этом причина, но сейчас же вот, пытаются CMake сделать стандартом де-факто, вроде бы хорошо получается, Conan тот же, пытаются и вроде бы тоже хорошо получается, т.е. можно все таки ? Я не уверен, что они имеют поддержку комитета и ко, а по мне должны иметь, хотя бы деньгами и/или людьми, т.к. это не только им надо, это же экосистема С++, которая как раз сводит все сложности к двум командам в терминале и магия :)

В том же pip, судя по интернету, PSF поддерживает финансово pip ровно с той целью о которой я и писал - развитие экосистемы. А у нас и не поддерживают и свою не ведут, сами разберетесь =D

Потому что комитету было пофиг на все, если коротко.

Это реально основная версия?

и в этом причина

Не в этом.

MISRA C++, clang-tidy и тп

Я затрудняюсь сейчас примомнить современный язык программирования без линтеров, guidelines и подобных инструментов. Вся индустрия больна?

Нет конечно, вы спросили что улучшить, я вам подсказал, что там вы среди "правил" пользования инструментом найдете кучу того что можно упростить или улучшить.

Я хотел сказать, что сложность входа была и так высокой, но комитет пробивает каждый раз новую высоту и продолжает ее пробивать выше. А зачем, если есть проблемы на поверхности, а страдать будут обычные разработчики, ежедневно :)

1.Последнее, что меня улыбнуло (в плохом смысле) - это корутины.
C++20 принял сам механизм корутин, однако никакого намека на std::task или подобных конструкций, которые позволяют использовать добавленный механизм без ручной реализации promise/линковки библиотек типа folly - нет. Даже тот же std::generator был добавлен аж в C++23, а не вместе с корутинами в C++20.

Да, возможно кто-то возразит, что нам дали упрощение типа std::suspend_always, но это все еще заставляет меня, как пользователя C++20 писать корутины ручками.

Полагаю, это как-то связано с работой над экзекьюторами, которые, к слову (надеюсь, наконец-то!) решат давний головняк с отсутствием std::future<T>::then. В данном случае я, кстати, до сих пор не понимаю, почему его до сих пор нет, хотя сам std::future скоро отметит 15-летний юбилей. К слову, в C++20 тот же std::future
не поддерживает co_await

2.Дисклеймер: не кидайте камнями за дальнейший текст, тк я все-таки не фанат Rust.
Личный гештальт: наверное больше половины моих кейсов использования вектора, это

std::vector<T> v;
v.reserve(n);

Что очень сильно начинает мозолить глаза после растовского Vec::with_capacity(n) . Мелочь - а как приятно!

3.Добавляя ложку меда: вообще, многие нововведения будущих стандартов довольно сильно радуют - рефлексия, контракты, mdspan, линейная алгебра и тд. Другой вопрос, что увидим мы это в продакшене году так к 2030'му, пока индустрия подтянется, ну да ладно, хоть модули спустя 5 лет где-то да появились. Однако зачастую, когда читаешь список пропоузалов в стандарт типа "разрешили делать using-декларацию в скобках for", невольно думаешь: "А нафига комитет тратит время на такие вещи, нужные дай бог раз в 500 лет в очень странном контексте, когда networking уже который стандарт все ждут?". Ну действительно, что мешает сделать этот using строчкой выше? Зачем усложнять грамматику и без того сложного языка, хоть убейте - не понимаю.

4.Не буду говорить про управление зависимостями и связанные вещи, тк на это уже не надеюсь. Все вроде смирились с тем, в каком мире мы живем.

P.S. Нисколько не хэйтерский комментарий, Антону за вклад в WG21 большой респект! Работа действительно очень сложная.

P.S. #2 Антон, а как дела с паттерн-матчингом? В свое время Александр Фокин делал доклад по данной теме на C++Russia, но я что-то в последних статьях особо ничего про него не вижу.

Антон, а как дела с паттерн-матчингом?

Увы, не успели к C++26. Буквально в последнее большое окно пытались решить все проблемы и протащить фичу, но она всё ещё оказалась "сыровата"

Ждём в C++29

То, что можно сделать функций вспомогателем не будет в стандарте без серьёзных аргументов.

template <typename Container>
constexpr Container with_capacity(size_t capacity)
{
   Container c;
   c.reserve(capacity);
   return c;
}

auto v = with_capacity<vector<int>>(10);

А вот с таскаи, да беда.
Есть пару попыток сделать нормально, но пока нет заинтересованности больших компаний видимо не будет продвижения.

https://github.com/lewissbaker/cppcoro
https://github.com/David-Haim/concurrencpp


В MSVC вообще есть свой Concurrency Runtime ( https://learn.microsoft.com/en-us/cpp/parallel/concrt/concurrency-runtime )

можно сделать функцией

Вы, несомненно, правы. Речь просто про удобство. Если сделать это свободной функцией:


а) нужно указывать тип контейнера, тк это не метод

б) в местах использования придется подключать header файл, где данная функция объявлена

в) следуя такой логике, видимо, сделали std::holds_alternative для std::variant . До сих пор удивляюсь, почему это не std::variant<Types...>::holds_alternative . Хотя мб я чего-то не догоняю о причинах такого решения)

На всякий случай упомяну, что речь шла про "личный гештальт". Я и не надеюсь на такой патч в стандарт. ( но было бы неплохо :) )

При создании вектора тоже надо указать тип. Тут нет в этом различия.

Да ещё одна функция. Но в стандарт не может предусмотреть на все случаи жизни. У нас будет книга на тысячи страниц тогда.

Насчёт holds_alternative, тут можно было бы сделать, но тогда в шаблонных классах пришлось бы писать v.template holds_alternative<T>.

Это ещё сложнее понять. К тому же есть свободные функции как get.

Хотелось бы, чтобы для лямбд try‑catch блоки, как для функций, разрешили без внешних {}, так как в рэнжах они частые гости. Раз разрешили кидать исключения в компилятайме, то для рефлексии это было бы полезным дополнением. Минус две фигурные скобки. Мне кажется, это легко реализуемо, и поправится лишь парсер и формулировка в стандарте.

Sign up to leave a comment.

Information

Website
www.ya.ru
Registered
Founded
Employees
over 10,000 employees
Location
Россия