Как стать автором
Обновить

Стандарт C++20: обзор новых возможностей C++. Часть 6 «Другие фичи ядра и стандартной библиотеки. Заключение»

Время на прочтение 13 мин
Количество просмотров 19K
Всего голосов 41: ↑40 и ↓1 +39
Комментарии 52

Комментарии 52

Нужен рефлекшин и сборка мусора.
Нет.
Комитет решил, что сборка мусора не нужна, и убрал её не далее, как два дня назад. Да-да, сюрприз, сборка мусора была, но ей по факту никто не пользовался. Поэтому комитет не стал делать её даже deprecated, а сразу исключил из Стандарта.
Хватит с нас и умных указателей. По факту, сборка мусора приносит гораздо больше проблем, чем пользы. Особенно, если мусора нет.

Рефлешн ждём)
Да-да, сюрприз, сборка мусора была, но ей по факту никто не пользовался.
Маленький комментарий к фразе, которая скорее всё запутала, чем объяснила.

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

Потому, разумеется, пользоваться ей никто не мог. Что и позволило её удалить без периода deprecated.
Убрал не потому что не нужна, а потому что плохо сделали, реально бесталково.

Если есть рефлекшн, то сделать автоматизированную сборку мусора легче легкого самому. Будет не хуже как в .NET. Ведь единственная трудность в сборке мусора в С++ в том что надо прописывать руками управляемые указатели в отдельных структурах. А так сделать автоматический гарбаджколлектор как в .NET. легко, сам делал, работал прекрасно и в многопоточных приложениях, но руками описывать структуры оказалось не слишком хорошо.
Сборку мусора никто не пользовал, потому что она нигде не была реализована, ни в одном компиляторе. А не потому что она никому не была нужна, она как раз нужна для огромного числа проектов.
По факту, мусор есть всегда и хорошо реализованная сборка мусора никаких проблем не приносит.

consteval очень полезная штука, для встроенного программирования, когда надо быть уверенным, что ваш код точно выполнится во время компиляции. Простой пример.

constexpr int getAddr(int startAddr)
{
 return addr + 10;
}

void write(int addr, int val)
{
 ...
}

int main()
{
  write(getAddr(10), 0);
}

Казалось бы все параметры для расчета адреса известны на этапе компиляции, но ребят ждет очень неприятный сюрприз: функция getAddr(..), без максимальной оптимизации будет вызвана в runTime и выполнит дурацкий расчет адреса.

Но кто об этом помнит?

А вот навешивание consteval на GetAddr(), позволило бы тут выдать ошибку, чтобы код немного подрихтовали.

int main()
{
  constexpr auto addr = GetAddr(10);
  write(addr, 0);
}
Супер, спасибо! Не знал, что есть ещё такая мотивация для consteval
Ну это — мотивация достаточно слабая. Использование constexpr-переменных для вычисления во время компиляции работает ещё в C++11 и consteval тут ровным счётом ничего не меняет.

Так, писать становится чуть-чуть проще — если не знать C++, то чуть больше вероятность что код всё равно будет работать так, как и задумано.

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

Что там нужно «рихтовать» в послднем примере — для меня вообще загадка (может было бы проще понять, если бы исходный код был без ошибок, а так вообще неясно кто и что имел в виду).
Фичи понятные и в целом неплохие, но вот что мне не нравится — программы на C++ постепенно превращаются в нечто громоздкое. Вот яркий пример — std::cmp_greater и подобные функции. Вместо чистой, привычной и компактной математической нотации x>y будет громоздкий вызов std::cmp_greater(x,y). Появляется очень много конструкций вида std::blahblahblah (и еще с аргументами, а то и с шаблонными аргументами), которые наверное зачем-то нужны, но скорее решают проблемы компилятора, чем программиста.

Еще интересно что в библиотеку bit не добавили bit reverse (RBIT в некоторых ассемблерах). Я писал автору вот этого предложения, и получил ответ — операция слишком редкая и экзотическая чтобы ее включать. Ну лично для меня она примерно на одном уровне экзотичности с битовыми сканами (поиск номера первого нуля или первой единицы) или popcount. Просто это достаточно фундаментальная операция, во многих архитектурах она есть — почему бы и в стандарте ей не быть?
Не «постепенно превращаются в нечто громоздкое», а уже превратилось. Это больше похоже на машинный код для машины, а не для человека. И конца и краю этому не видно.
Ну это Вы зря. На практике с каждой версией стандарта код становится всё лаконичнее и лаконичнее. Другое дело — что с каждой версией разработчикам нужно привыкать к новым фичам.

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

И это если сравнивать код на C++20 и 17. Разница же между C++20 и 98 видна невооруженным взглядом.

Как и с любыми другими наборами инструментов, стандартную библиотеку нужно уметь использовать. Впрочем, за исключением буквально пары языковых фич, не работающих без поддержки со стороны стандартной библиотеке (std::inializer_list, std::type_info, например), использовать std вовсе не обязательно. Можете написать свою, или использовать сторонние.
По существу С++ перетаскивает все фичи из C#, но при этом код становится не более читабельным, а более нагруженным, похож на китайскую грамоту. Всё что Вы описали давно есть в С#. но там нотация не усложняет код и там действительно код становится проще.

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

Ни в коем случае не хочу сказать, что C# хуже C++, а к тому, что для объективного сравнения нужно владеть обоими языками и их стандартными библиотеками в равной мере. Лично я в последнее время отошел от шарпов, и развитие плюсов кажется закономерным и ожидаемым, Вы, видимо, наоборот.

Что же до перетаскивания фичей — так этот процесс со всеми языками идёт, идеи распространяются и эволюционируют.
Эм… интересно где это он раздулся. за 5 версий появились пара ключевых слов и паттерн-матчинг… В последний раз я писал на плюсах в 12том году. Это — я просто не могу прочитать уже без боли(спорить о полезности я не могу здесь). А шарп по сути и не изменился.
К сожалению, последний опубликованный language reference по C#, который мне удалось найти — только 5ый, так что сравнить его длину с 9ым не получается по чисто техническим причинам. Впрочем, референс по C# 5 занимает приблизительно 500 страниц, возьмём за отправную точку.

Вроде немного по сравнению с C++ (в документе n4830, например, их уже аж 1802 штуки). Однако в стандарте C++ описан не только язык, но и стандартная же библиотека, в то время как BCL в референсе по языку отсутствует, что довольно логично, но мешает сравнить.

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

Если хотите уровнять наши страдания, можете тоже предложить мне посмотреть на какой-нибудь кусок кода на шарпах, я попробую рассказать, что кажется неправильным мне =)
… 5 6 7 7.1 7.2 7.3 8 9 (вроде так.)
5 — добавили async — await. (хрен знает когда)
в 7 добавили стек-онлин структури ref structures, и кажется «in» (что-то вроде const T*.
в 9том = record и пол мелочи.

Может спецификация и увеличилась… Код стал чуть короче, разве что.
Главное, что он стал гораздо быстрее. По сути, если хочется скорости, то смысла писать модуль на чем-то нативном, я теперь не вижу.

Про боль, я очень не люблю обилие дужек, скобок. Так то я понимаю что написано. Постепенно и в шарпе появляется вещи типо!!! или ?!.. Мне это не шибко нравится, с эстетической точки зрения.

В Шарпе в принципе очень трудно сделать так, чтобы код было трудно прочитать, так что я уверен, что Вы без проблем разберётесь в любом коде:)

Так ведь ради краткости и эффективности кода ведь всё и задумывается, причём в эту сторону движутся и C#, и C++, и все остальные языки программирования!

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

Давайте, например, посмотрим на одну из сложнейших языковых фич, корутины: смотрите, вот, к примеру, 250 строк жуткого кода , описание шаблонного типа generator. Без поллитры не разобраться, не правда ли?


Однако это - библиотечный тип, его реализовали один раз опытные люди, и теперь простым смертным достаточно его только использовать:

#include <cppcoro/generator.hpp>

using namespace cppcoro;
using namespace std;

generator<uint64_t> fibonacci()
{
    uint64_t a = 0, b = 1;
  
    while (true)
    {
        co_yield b;
    
        auto tmp = a;
        a = b;
        b += tmp;
    }
}

void usage()
{
    for (auto i : fibonacci())
    {
        if (i > 1'000'000) break;
        cout << i << endl;
    }
}

В C# это выглядело бы примерно так:

using System;
using System.Collections.Generic;

IEnumerable<UInt64> Fibonacci()
{
    UInt64 a = 0, b = 1;
  
    while (true)
    {
        yield return b;
    
        var tmp = a;
        a = b;
        b += tmp;
    }
}

void Usage()
{
   foreach (var i in Fibonacci())
   {
       if ( i > 1000000 ) break;
       Console.WriteLine( i );
   }
}

Велика ли разница? :)

Как видите, страшные языковые и библиотечные возможности понадобились для реализации типа самой корутины (IEnumerable в C# - почти полный аналог generator, а Task весьма похожа на нашу future (правда, в полнофункциональном виде пока существующую не в стандарте, а только в реализации Microsoft) ).

В C# опытные программисты тоже реализуют поддержку yield return / await у произвольных типов, и это такая же нетривиальная задача, как в C++.

Благодарю за развернутый ответ!
Да, похоже Вы правы. Видимо просто нужно больше кода почитать на современном Сpp

Круто, появились корутины.

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


PS Вы вообще пост не читали перед комментированием, да?


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

это ведь на основе Fiber? или я неправильно понимаю?

Upd.
а, вижу ссылку. ТО еще не читал.

О каком Fiber вы говорите? Нет, сопрограммы в С++ никаких Fiber не используют.

Хотел только добавить, что Вы зря прибедняете C# насчёт корутин :)

Там они именно что есть, да ещё и в двух разных вариантах, обуславливаемых разными синтаксическими конструкциями - yield return / yield break и await.

Более того, именно из C# корутины приехали в C++, это было предложение Майкрософтов, вдохновлённое наработками из развиваемого ими языка.

Только корутины в C++, будучи развитием уже отработанного подхода, чуть более универсальны: у нас тоже есть три ключевых слова co_yield, co_return и co_await, (на "кококо" все ругаются, но Комитет побоялся использовать для ключевых слов распространённые английские слова, чтобы не ломать обратную совместимость) но по сути это всё - частные случаи оператора co_await.

Прежде чем критиковать пост, нужно тоже внимательно его прочитать… так что

«Это — я просто не могу прочитать уже без боли(спорить о полезности я не могу здесь).»

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

Типичные жители хабра, всё агрессивно воспринимают. Дисскусия завершена.
Просто это достаточно фундаментальная операция, во многих архитектурах она есть — почему бы и в стандарте ей не быть?
А в каких алгоритмах она нужна? Я лично в реальных программах видел её только на ARM и только потому, что там CTZ нету. Этот вариант её использования покрывает countr_zero.

Я бы скорее сказал что операция, которая на многих архитектурах дико неэффективна и мало кому нужна — явно не заслуживает включения в стандарт.
Гораздо большее изумление вызывает, что не добавили элементарную конвертацию LE <-> BE.
Если конечно её действительно нет, потому что это уж очень странно выглядит, что enum для Endian добавлен, а такой простой и нужной функции нет.
Было бы замечательно, если бы придумали как для шаблонных классов реально разделять объявление и реализацию. А не простое раскидывание на инклюды.

С разделением по инклюдам неудобно разделяются взаимно используемые шаблонные классы. И существенно тяжелей становится при компиляции, модификация файла реализации приводит к перекомпиляции всех файлов куда включен этот класс. Функции с параметрами auto не закинуть в файл реализации.

Решение этого вопроса существено улучшило бы вопрос масштабирования проектов.
Или может такое уже есть, и я пропустил?
Шаблонный класс это фактически макрос, который разворачивается при каждом использовании шаблона с новыми параметрами. Если сделать, как вы хотите, выделить реализацию так, чтобы не требовалась перекомпиляция всех использовавших шаблон классов при изменении реализации, это снизит эффективность сгенерированного кода, что недопустимо для C++
То, что шаблоны это инстанцирование в момент компиляции, это практически всем известно. А снизит эффективность выполнения это в том случае, если делать таким путем который снизит эффективность. А вот если придумать способ который не снизит, тогда будет такой способ.

Как вариант делать какую-нибудь компиляцию во время линковки. Она утяжелит линковку таких файлов, но на меньшее, чем утяжеляется полная перекомпиляция. Это все же не define.

Delphi к примеру уже давно заделал свой промежуточный формат либов, а объектники использует уже в конечной компиляции. И в результат существенно быстрее компилится. Давно я уже не связывался с ним, но тем не менее.

И опять же, вопрос компиляции это лишь часть вопроса. Другой вопрос в масштабировании проекта.
Как вариант делать какую-нибудь компиляцию во время линковки
Ну и какая разница? В MSVC в макс. оптимизации работает link-time code generation, которая позволяет заинлайнить ф-ции из скомпиленных obj-файлов, а не просто их вызвать по известному символу. Но это делает линковку очень медленной. При изменении одного cpp файла, перекомпилируется только он, очень быстро, а дальше — жди полчаса, пока всё слинкуется…
Переработка в инлайны имеет совсем другую логику. Нужно перекомпиливать код других объектников, заменяя вызовы на инлайны.

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

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

Вот только выяснилось, что на практике распарсить синтаксис — примерно 1% работы. Хотя синтетические примеры можно сделать и патологическими, такими, чтобы парсинг занимал больше времени, да. Но на практике — ускорять ту часть, которая и так занимает ничтожное время… не имеет смысла.
Это не меняет основного смысла моего поста.
Ваш пост, вроде бы, о проблемах масштабирования. Но где они?
У нас, не так давно, пилили самый большой бинарник в системе ибо он перестал ликоваться, количество кода превысило 2GiB. Но это ограничение x86-64 архитектуры, как очередная ревизия C++ тут может что-то исправить?
В случае же шаблонов, при изменении реализации какого-либо из методов, ее сигнатура не меняется. Поэтому другие объектники не нужно переделывать.
Допустим, у меня есть шаблон vector[T] (скобки квадратные, т.к. парсер Хабра режет угловые). И в каких-то других классах он используется как vector[int] и vector[string]. Вы предлагаете вынести реализацию в отдельный cpp-файл, чтобы obj лежал скомпиленный и перекомпилялся только при изменении реализации. Но в obj-файле какие классы должны лежать? Логично, что vector[int] и vector[string]. Но на момент компиляции реализации откуда мы узнаем, какие в проекте есть все инстанциации шаблона? А если появляется инстанциация с новым типом, таки придётся перекомпиливать реализацию шаблонного класса, хоть её cpp-файл и не менялся?
Вы это правильно говорите, что без существенной переработки obj это не реализуется. Возможно поэтому это и не делают.

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

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

Объявления шаблонных классов по прежнему остаются в хедере, что позволяет другим объектникам определять нужные сигнатуры вызовов.
А вот если придумать способ который не снизит, тогда будет такой способ.
Мечтать не вредно. Если кто-то изобретёт аппарата для телефортации, так и авто с ДВС и электромобили разом устареют.

То же самое и тут: можно либо реализовать дженерики (эффективные на стадии компиляции, но не исполнения), либо шаблоны (у которых всё наоборот) — а третьего варианта нет. С 1998 года по 2011 (когда предлагаемая вами фича была в стандарте, но не в существующих компиляторах) её никто не смог изобрести и в C++11 её просто убрали и из стандарта тоже.

Delphi к примеру уже давно заделал свой промежуточный формат либов, а объектники использует уже в конечной компиляции. И в результат существенно быстрее компилится.
Да разве только Delphi? Ada, C#, Go, Java… «тысячи их». Но чудес же в мире не бывает. Либо у вас быстрая компиляция, либо быстрый код.

C++ предлагает модули, но они компиляцию не ускоряют, они решают проблему «протекания реализации в интерфейс».
Помнится достаточно давно разработчики компилятора от Intel заявляли, что ICC может легко реализовать разделение шаблонов на объявление и реализацию, но этого не делают из-за требований совместимости с MSVC, который подобного не умеет и не планировал.
Тут не то, чтобы разработчики MS виноваты. Они уже это умеют делать с LTCG (см. сообщение выше). Просто в этом случае получающиеся obj-файлы несовместимы не то что между MSVC и ICC, а даже между разными билдами MSVC.

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

Причём стандарт должен быть создан не в одностороннем порядке от MS, а принят всеми участниками: MS, Intel, IBM,… Кто там ещё остался в разработчиках компиляторов? Тут Intel либо недопонимает масштаб задачи, либо просто нашли на кого перевести ответственность.
Мы немного про разные вещи говорим. Речь не про obj и прочее.
MSVC сделан так, что для него имплементация шаблонной функции в срр файле невозможна. Вина ли это MS? Да как бы и нет, стандарт не требует. Intel заявляли что могут, но их рынок ICC много меньше чем рынок MSVC и по большей части это узкооптимизированные сборки, при этом часто разработка выполняется на MSVC и только финальный релиз собирается ICC.
Поэтому совместимость с компилятором от микрософт для Intel много важнее, чем новые фишечки собственного компилятора. Тем более, что «стандартом не требуется».
Так причём тут MS? По сути, Intel хочет компилировать не C++, а какой-то другой неведомый язык. С тем же успехом Intel может говорить, например о Go или о Rust, какой язык хороший и какой у них есть компилятор для этого языка, но мол проблема в том, что разработка выполняется в MSVC и поэтому их хороший язык не получает использовать.

Пусть идут в комитет по стандартизации и пропихивают там такой синтаксис в C++, Microsoft без проблем его реализует, как только он появится в стандарте.
Такой механизм был в С++03, это делалось ключевым словом export, но его исключили из Стандарта в 2011 из-за сложности реализации. К тому моменту смогли реализовать только EDG в своём компиляторе.

В принципе не очень понятно, зачем в 2021 году отделять объявления от определений. Единственное, что приходит в голову, как было отмечено — когда классы друг на друга ссылаются. В таком случае можно оформить один класс как вложенный. А если такой подход не соответствует ситуации, то мне кажется, нужно задуматься об архитектуре приложения.

С переходом на модули будет ещё меньше поводов отделять определения от объявлений. И понятие «файла реализации» вообще станет рудиментом прошлого (хотя модули их и допускают).
К тому моменту смогли реализовать только EDG в своём компиляторе.
Только у EDG нет и никогда не было компилятора. У них только фронтэнд и кой-какие ещё тулы. А компилятора нет.

С переходом на модули будет ещё меньше поводов отделять определения от объявлений. И понятие «файла реализации» вообще станет рудиментом прошлого (хотя модули их и допускают).
Скорее всего на модули мы будем переходить уже в C++23. Просто потому что пока ещё инфораструктура не готова, есть только стандарт, а как их попытаются практически использовать — косяки полезут.
Впечатляет. Теперь все эти фичи надо попробовать на уровне семплов, а когда это войдет в повседневную практику, не вполне ясно. Лично я сейчас неплохо ориентируюсь в C++17, но применяю его фичи не часто. Похоже многие руководители не горят желанием переходить на современные версии компиляторов, объясняя это необходимостью совместимости со старыми стандартами. Например в VS2019 по умолчанию C++14, а C++17 и последний стандарт надо включать специально. Правда на днях было обновление до 16.10.0 в котором C++20 поддерживается ощутимо лучше.
> в котором C++20 поддерживается ощутимо лучше.
Судя по табличке cppreference.com, там уже почти все фичи реализовали, как библиотечные, так и языковые (хотя недоделки и есть, куда без них).

Честно говоря, тоже ещё не привык думать в стиле c++20, однако при освоении 17ых те же чувства были, правда? Значит, пара месяцев практики — и новой версии начнёт не хватать =)

С поддержкой новых компиляторов, к сожалению, «жиза»… У нас, например, только-только на C++17 переходят, и это не так уж плохо, есть гораздо более консервативные проекты.
C++17 по сравнению с новым Стандартом куда более лайтовый =)

А Microsoft действительно молодцы. Поддержали почти всё. У них кстати есть своя актуальная таблица соответствия.
Тут есть проблема. Фичи в компиляторах C++ проходят не две стадии, а три:

  1. Фича не поддерживается.
  2. Фича поддерживается.
  3. Фичей уже таки можно пользоваться.

И вот тут тот факт, что Microsoft — коммерческая компания играет злую шутку.

Переход из #1 в #2 наверняка измеряется KPI. И это в Microsoft делают чуть ли не быстрее всех остальных. Скажем тот же пресловутый «космический корабль» из стадии #1 в стадию #2 перешёл два года назад. Даже победную статью тогда же написали.

А как там с #3? Ну как-как. Clang 11 — да, GCC 12 — да, MSVC… пока нет.

Улита едет, когда-то будет… интересно только до того, как они SFINAE до третей стадии доведут или после. Сколько там они уже лет не могут проблемы со SFINAE исправить? 20? 30?
Ухх, спасибо огромное за примеры, лично я даже не подозревал о такой подставе с <=> =)

Без нормальных оптимизаций использовать эту штуку вместо операторов сравнения действительно страшновато.

С другой стороны, это детали реализации, рано или поздно вендоры доведут её до ума, и с каждой версией компилятора программы могут становиться быстрее и быстрее, а писать их вполне можно начинать уже сейчас.
Попробовал многое из описанного, VS2019 версия 16.10.0. Действительно Microsoft молодец, почти все реализовано. std::format почти 1 к 1 как в C#. По поводу некоторых других фич возникает вопрос: почему такие простые и нужные вещи появились только сейчас (std::numbers::pi, std::string::starts_with()).
Теперь типы char16_t и char32_t явно обозначают символы в кодировках, соответственно UTF-16 и UTF-32. Ещё добавили новый тип char8_t для UTF-8.

Это просто типы, которые могут хранить code point кодировки UTF-XX? Есть примеры, как это используется на практике? Т.е. я вижу специализации std::u8string, std::u16string, std::u32string, но они же не юзабельны:


  • что std::u8string::size(), что std::u8string::length() вернут одно и то же число
  • operator[] вернёт не нужную последовательность UTF, а просто code unit. Аналогично и с at()
  • итерация тоже будет по code units

И это в мире, где уже куда не плюнь, а в UTF-8 попадёшь.


Потрясающие новости: теперь в Стандарте есть π.

Вкупе с предыдущим, звучит как издевательство :-D


Новые алгоритмы: shift_left и shift_right

Нужно поковырять с bitset… Насколько оно соптимиздиться сможет до v<<x :-)


Появился новый тип span

Давно хотел. Но ему в противовес не хватает std::view, с тем же набором поддерживаемых контейнеров.


Также файл определяет новый тип std::endian

Как я этого ждал! Жаль, что там, где это было нужно, не будет gcc 12+ :-D


у string теперь есть методы starts_with и ends_with

Вот же реальное недоразумение было :) Ещё научить работать версии std::uXXstring с символами, а не код-поинтами (с выше).


В Стандарт добавился набор из шести новых функций для сравнения целых чисел

А я на проекте писал всякие safe_cmp, safe_diff как раз на этот случай.


Закончим обзор на радостной ноте: в C++ существенно упростили многопоточное программирование.

При этом для низкоуровневого программирования не хватает интерфейса к аналогу pthread_attr_t. Как минимум в контексте передачи размера стека для потока при его создании, что ОЧЕНЬ нужно во всяких RTOS и без чего существующий интерфейс std::thread малопригоден. Частично это уже реализовано в boost::thread, ЕМНИП.

Ну вот как раз методам starts_with и ends_with нет разницы с код-поинтами или с символами они работают, пусть и благодарить надо за это не авторов стандарта, а авторов UTF-8

На сколько помню, format тащили по образу и подобию libfmt. Но что действительно жаль, так это то, что затащили его не весь. fmt::join например очень полезная фишка.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий