C++26 (C++26)
Эту статью предлагается удалить. |
Эта статья во многом или полностью опирается на первичные источники. Такие источники рассматриваются как нежелательные. А если они не опубликованы, то они не допустимы по правилу проверямости. |
Возможно, эта статья содержит оригинальное исследование. |
C++26 или C++2c (латиницей), или Си++26 (кириллицей) — ожидаемый стандарт языка программирования C++. Разработка началась сразу же после того, как в феврале 2023 года зафиксировали C++23.
С самого начала стандарт получил рабочее имя «Си++26». Си++0x должен был приблизить устаревающий Си++ к современным языкам, непрерывно разрабатываемым под руководством единоличника. (Си++ разрабатывается комитетом и есть много реализаций — в отличие от, например, Python.) Но стандарт запоздал, и с версии 14 новый язык выпускают не «когда готово», а раз в три года, при этом последний год — только доводка. КОВИД не сместил расписание — к пандемии как раз была готова версия 20, а версию 23 подготовили дистанционно.
Заседания
[править | править код]- 12…16 июня 2023, Варна (Болгария)[1] — первое после пандемии КОВИДа очное заседание.
- 6…11 ноября 2023, Каилуа-Кона (Гавайи, США)[2]
- 18…23 марта 2024, Токио (Япония)[3].
- 24…29 июня 2024, Сент-Луис (Миссури, США)[4]
- 18…23 ноября 2024, Вроцлав (Польша)[5]
- Февраль 2025, Хагенберг-им-Мюлькрайс (Австрия) — ожидается
- Июнь 2025, София (Болгария) — ожидается
- Ноябрь 2025, Каилуа-Кона (Гавайи, США) — ожидается
Запрещены и удалены
[править | править код]Запрещены в языке
[править | править код]void f(int x...);
— старый редкий синтаксис переменных параметров Си на разборе стека черезva_list
[6]. Остаётся добавленный позже Си-совместимыйvoid f(int x, ...);
. Возможно, это шаг к синтаксису «сколько угодно параметров int» шаблонного типа, то есть создающему отдельную функцию для нуля, одного, двух параметров[6].
Удалены из языка
[править | править код]- Любые операции между
enum
и дробным;enum
и другим enum. Ошибкоопасное наследие Си. Запрещены в Си++20, операция «звездолёт»<=>
никогда не разрешалась[7]. Использовать явное преобразование типов. Может помешать совместимости с Си, обходится легко:+C1 + C2
. - Функции больше не могут возвращать ссылку на временный объект[8]. На именованный стековый пока ещё могут. Поведение
is_convertible_v<int, const double&>
не изменяется — константа остаётсяtrue
, ведь преобразованиеint → const double&
законно в других местах. - Некодируемые строковые литералы (например, из-за отсутствия конкретного символа в кодировке исполнения) теперь ошибочны[9]. Многосимвольные литералы
'abc'
не могут иметь префикса кодировки, и могут состоять только из символов, укладывающихся в один байт (или другую кодовую единицу) каждый. - Уничтожение объекта недоопределённого типа (
class X;
) операциейdelete
, даже без запрета (неофициально запрещён большинством компиляторов)[10]. Менеджер памяти знает размер выделенного участка и ему не нужна информация о типе. Но раньше предполагалось, что деструктор ничего не делает, что может снижать взаимозависимость между единицами трансляции в настоящем, но если в будущем тривиальный объект станет управляемым, будет утечка памяти. - Сравнение массивов. Они сравнивались как указатели, и с операцией «звездолёт» (Си++20) были запрещены[11]. Обходится легко:
+a == b
, нужно редко.
Диагностика доступа до инициализации
[править | править код]Доступ до инициализации — это известный источник ошибок, и теперь запрещён в очень ограниченном виде — только на стеке[12]. Если действительно неопределённое значение нужно — использовать новый атрибут [[indeterminate]]
.
union
всегда считается инициализированным полностью. На объекты в «куче» диагностика не распространяется.
void h() {
int d1, d2;
int e1 = d1; // теперь ошибка
int e2 = d1; // теперь ошибка
assert(e1 == e2); // OK
assert(e1 == d1); // выполнялось, теперь ошибка
assert(e2 == d1); // выполнялось, теперь ошибка
std::memcpy(&d2, &d1, sizeof(int)); // OK, но у d2 теперь ошибочное значение
assert(e1 == d2); // выполнялось, теперь ошибка
assert(e2 == d2); // выполнялось, теперь ошибка
}
void f(int);
void g() {
int x [[indeterminate]], y;
f(y); // ошибка
f(x); // неопределённое поведение
}
Запрещены в библиотеке
[править | править код]is_trivial
. Использовать конкретные особенности типа: если нам важно тривиальное конструирование и уничтожение, но не важно присваивание — значит,is_trivially_constructible && is_trivially_destructible
[13].- Само определение тривиального типа сложное: хотя бы один действующий (то есть не исключённый явно через
=delete
или неявно) конструктор/операция копирования/переноса, все они, если действуют, то тривиальны. Также тривиальный конструктор без параметров и тривиальный деструктор.
- Само определение тривиального типа сложное: хотя бы один действующий (то есть не исключённый явно через
Удалены из библиотеки
[править | править код]- Весь заголовок
<codecvt>
— нет обработки ошибок[14]. Запрещён в Си++17. Использовать внешние, более управляемые функции. allocator<T>::is_always_equal
[15]. Ошибкоопасен при наследовании от аллокатора, в котором этот is_always_equal есть. Запрещён в Си++20, для проверки возможностей аллокатора использоватьallocator_traits
. Использовать в собственных аллокаторах, когда это действительно играет роль.string.reserve()
без параметров, эквивалентныйreserve(0)
[16]. Со старым API строк (Си++98…17) использовалось какshrink_to_fit
, им же и заменено. В Си++20reserve
больше не укорачивает строку, а данную перегрузку запретили.strstream
(поток, который пишет в буфер памяти) — запрещён давно в Си++98 из-за опасности переполнения буфера[17]. Использоватьspanstream
(Си++20).wstring_convert
(преобразование кодировок из многобайтовой в Юникод, заголовок<locale>
) — запрещено в Си++17 из-за сложности[18][19].- Атомарный API
shared_ptr
— запрещён в Си++20, использоватьatomic
[20].
Снят запрет
[править | править код]polymorphic_allocator.destroy
— запрещено в Си++20. Пусть это же можно сделать и черезallocator_traits
, так короче[21].
Язык
[править | править код]Разные изменения в языке
[править | править код]- Параметром-значением в шаблонах (non-type template parameter) может стать и вызов конструктора. Указано, когда такой вызов возможен, а когда нет[22].
- Теперь можно навешивать атрибуты и на структурные переменные:
auto [a, b [[vendor::attribute]], c] = f();
[23]. Предложенное назначение — аннотирование кода для углублённой проверки на безопасность: например,char*
в данном месте не требует закрывающего нуля. - Структурные переменные в условных операторах сами могут быть условием, если для структуры в целом существует надлежащее преобразование в bool:
if (auto [first, last] = parse())
[24]. Или, вместе с новыми изменениями в библиотеке:if (auto [ptr, ec] = std::to_chars(p, last, 42)){}
[25].
Конструируемые строки в static_assert
[править | править код]Для начала придумали понятие «не вычисляемая строка» (unevaluated string): закавыченная строка, значение которой не проходит в скомпилированную программу, а нужно только компилятору. Они являются частью _Pragma
, asm
, [[nodiscard]]
… — и, конечно, static_assert
[26]. Им запрещается иметь префикс кодировки.
Впоследствии позволили в static_assert
любую константно вычисляемую строку[27]:
// Было
template <typename T, auto Expected, unsigned long Size = sizeof(T)>
constexpr bool ensure_size() {
static_assert(sizeof(T) == Expected, "Неожиданный sizeof");
return true;
}
static_assert(ensure_size<S, 1>());
// Остаётся надеяться, что компилятор напишет, что дело было в ensure_size<int, 1, 4>
// Стало
static_assert(sizeof(S) == 1,
std::format("Неожиданный sizeof: хотел 1, получил {}", sizeof(S));
// Неожиданный sizeof: хотел 1, получил 4
constexpr format
намеренно не внесён, но его прообраз, библиотека libfmt, уже способна на constexpr.
i-й элемент пакета параметров
[править | править код]Теперь его можно получить как T...[i]
. Например: void f(T&&... t) { g(std::forward<T...[0]>(t...[0])); }
[28].
Формально это несколько бьёт по имеющемуся коду: void f(T...[0]){}
представляло собой пакет безымянных массивов, но по факту не покрыто тестовыми программами и даже не компилировалось в MSVC и G++. C# и D поддерживают и i-й параметр с конца, но отрицательные числа для этого ошибкоопасны, а более сложный синтаксис решено не просить.
Эта функциональность, написанная на шаблонах, даёт O(n) специализаций[29]. В CLang, а за ним и в G++ реализовано «волшебным» (встроенным в компилятор) шаблоном __type_pack_element<i, Types...>
и используется, например, в variant
.
Имя _
может повторяться
[править | править код]auto [where, _] = insert();
— давно устоявшаяся манера программирования, когда функция возвращает два поля, а нужно одно, особенно если возвращается неговорящий тип вроде pair
. Второй вариант — когда нужен именованный (не временный) объект, но имя не важно: захват мьютекса lock_guard _(someMutex)
. На случай, когда таких подчерков несколько, идиому расширили:[30]
namespace a {
auto _ = f();
auto _ = f(); // Остаётся ошибка: с глобальными переменными не работает
}
int _;
void f() {
using ::_; // Остаётся OK, добавление в пространство имён постороннего символа
auto _ = 42; // Теперь OK
using ::_; // Остаётся ошибка: using _ разрешено только до локальной _
auto _ = 0; // Теперь OK
static int _; // Остаётся ошибка: со статическими переменными не работает
{
auto _ = 1; // Остаётся OK, замещение
assert( _ == 1 ); // Остаётся OK, имеем дело с замещённой переменной
}
assert( _ == 42 ); // Ошибка: которая из двух?
}
Использование или неиспользование имени в этом контексте не должно вызывать предупреждений.
Для функций, типов, using X=Y
, концепций и шаблонных параметров новый механизм бесполезен: этим объектам либо нужно говорящее имя, либо Си++ уже даёт подходящие механизмы вроде безымянных типов.
Расширен constexpr
[править | править код]- Преобразование указателей в
void*
, а потом обратно в свой тип[31]. Преобразование в посторонние типы неконстантно. Используется для так называемого стирания типа — при выполнении информация хранится в переменной общего типа, но её обработка выстраивается так, что все преобразования в частный тип верны. (Так устроены, например, обобщённые типы Java.) В CLang механизм уже есть (потребовался для выделения памяти) и вынести наружу ничего не стоит, G++ и EDG не видят препятствий. По заявлениям Г. Саттера, это шаг кconstexpr format
[32]. - Предыдущее изменение привело к тому, что теперь можно сделать constexpr placement new, допустимый только если указатель действительно смотрит на свой тип, и являющийся простой инициализацией[33]. Воспользовавшись нововведением, перенесли в constexpr библиотеку неинициализированной памяти (Си++17).
- Constexpr-указатели, ссылки и структурные переменные, представляющие собой просто название по имени того или иного constexpr-объекта[34].
- Выброс исключений с последующей обработкой[35]. Но в любом случае авария не должна выпадать наружу, иначе это не constexpr: вычисляется при исполнении, если контекст позволяет, и ошибка — если нет. Раньше уже факт выброса снимал constexpr. Некоторым наиболее распространённым исключениям сделан
constexpr what()
.
Вариативный friend
[править | править код]Одно из назначений оператора friend
— объекты-утилиты, сделанные через саморекурсивные шаблоны. Если шаблон вариативный, то друзей может быть много.
Пример: так называемый passkey, идиома Си++, используемая, если скрытую функцию надо вызвать из несвязанного шаблона (обычно make_unique/make_shared
). Чтобы шаблон имел к ней доступ, функция должна быть общедоступной, и скрывают не её, а параметр-затычку, так называемый passkey, который так просто не получишь.
// Вариативный passkey
template<class... Ts>
class Passkey {
friend Ts...;
Passkey() {}
};
class C {
public:
// Можно вызвать только из Blarg, Blip и Baz
void intentional(Passkey<Blarg, Blip, Baz>);
};
// Раскрыть класс для внутренних объектов
template<class... Ts>
struct VS {
template<class U>
friend class C<Ts>::Nested...;
};
Разрешение вариативных шаблонных перегрузок с концепциями
[править | править код]Для простой шаблонной перегрузки с концепциями 1-2 уже прописано: если подходят несколько шаблонных функций, брать ту, чьи ограничения сильнее. То же самое сделано и для вариативной 3-4, очень сложным языком. «Почти правильный» код Си++23 может перестать компилироваться в 26[36].
template <std::ranges::bidirectional_range R> void f(R&&); // №1
template <std::ranges::random_access_range R> void f(R&&); // №2
template <std::ranges::bidirectional_range... R> void g(R&&...); // №3
template <std::ranges::random_access_range... R> void g(R&&...); // №4
void call() {
f(std::vector{1, 2, 3}); // OK, №2 сильнее
g(std::vector{1, 2, 3}); // Теперь OK, №4 сильнее
}
=delete("причина")
[править | править код]Иногда нужно отказаться от автоматического присваивания, одной из унаследованных функций или нежелательного преобразования типа. В Си++03 функцию удаляют заголовком без тела, по возможности скрытым private: void f();
. В Си++11 появилось тело =delete
: компилятор, а не линкер явно сообщает о недопустимом вызове. По словам источника, «автор библиотеки говорит: „Я знаю, что вы думаете делать, и это неверно“».
Нововведение дополнительно сообщает программисту, почему функция удалена и что делать — «…и это неверно, и я скажу, почему неверно и как надо». Например: Proxy<T> factory(const T&&) = delete("Опасно висячими ссылками");
[37]. Другие приведённые в источнике причины: старый API выброшен и отсылает на новый, некопируемый/труднокопируемый тип, недопустимое конструирование строки из nullptr
, неправильный синтаксис создания динамического массива функцией make_unique
.
Существуют предложения сделать условный =delete
, как это сделали с explicit(bool)
(Си++20) и noexcept(bool)
(Си++11), но, по заверениям заявки, данный синтаксис не бросит на это тень.
Пакеты в структурных переменных
[править | править код]Синтаксический сахар для сложных шаблонов, разбирающих объект-кортеж на части[38]. Это работало и раньше — только на уровне библиотеки.
auto [x,y,z] = f(); // остаётся OK
auto [...xs] = f(); // новое
auto [x, ...rest] = f(); // тоже новое
template <class P, class Q>
auto dot_product(P p, Q q) {
auto&& [...p_elems] = p;
auto&& [...q_elems] = q;
return (... + (p_elems * q_elems));
}
Редакционные правки
[править | править код]- Разрешены разночтения в лексическом анализаторе: сращиванием строк текста через
\⤶
и склеиванием лексем через препроцессорное##
можно получить имя символа; переводы строк внутри закавыченной строки запрещены. Это статус-кво, поддерживаемый G++, CLang и EDG[39]. - Некодируемые строковые литералы (например, из-за отсутствия конкретного символа в кодировке исполнения) ошибочны[9].
- Уточнены правила игнорирования стандартных атрибутов[40]:
- Стандартный атрибут должен быть корректным по правилам текущего Си++, даже если игнорируется. (Уже в Си++23[32] и только добавлено примечание.)
- У стандартных атрибутов необязательная семантика: убирание атрибута из корректной программы может менять её внешнее поведение, но не может придумывать новое — лишь ограничить до одного из допустимых вариантов, когда атрибут есть, и, возможно, убрать какие-то компилятороспецифичные гарантии. (Также в Си++23 и добавлено примечание.)
- Псевдофункция препроцессора
__has_cpp_attribute
должна проверять, реагирует ли компилятор на данный атрибут (а не разбирает ли) — а если разбирает, но не реагирует, атрибут бесполезен и макросы совместимости должны развёртываться во внутренние функции вроде__builtin_assume
. (А это новое правило.)
- Объявлено, что объект
initializer_list
ссылается на опорный массив, который может появиться в памяти двумя способами: как временный объект или как ссылка на какой-то массив, чьё время жизни продлено[41]. Другими словами, нет нужды копировать из сегмента данных на стек, теряя в производительности и надёжности. - Требования к
generate_canonical
переписаны так, чтобы работало на недвоичных машинах, сохранялись статистические свойства на всём диапазоне [0,1) — и результирующее число никогда из-за недостатков дробной арифметики не стало бы единицей[42]. В результате может нарушиться повторяемость — на том же генераторе случайных битов могут выходить другие дробные. - Переписано, когда можно опускать скобки при агрегатной инициализации:
Point x[2] = { 1, 2, 3, 4 };
[43]. - Заголовок модуля
export module Name;
не может быть макросом — это усложняет его обработку системой сборки[44]. Импорт может — не вызывает таких сложностей. - Пустой бесконечный цикл — больше не неопределённое поведение[45]. CLang в таких ситуациях почему-то исполнял посторонний код.
- Выкинуты все
[[nodiscard]]
из стандарта в отдельный документ, описывающий оптимальную практику, в каких случаях его применять[46]. Предполагается, что изменения в этот документ будут вноситься легче, чем в стандарт. Один пример: правило MISRA C++ 28.6.4 запрещает вызывать как процедурыremove[_if]
,unique
иempty
[47] — наempty
аннотация была, чтобы не путали сclear
, а на остальных не было (результат нужен в дальнейшемresize/erase
). - Упрощены грамматические правила для литералов[48].
- Уточнена работа операций сравнения в
expected
[49]. - На стыке диапазонов, алгоритмов и разрешения перегрузки в пространствах имён возник специфичный вид объектов, призванных не вызывать функции из
<algorithm>
— ниблоиды (niebloids), в честь Эрика Ниблера, автора библиотеки диапазонов. Реализованы Ниблером в изначальной библиотеке, подхвачены G++, CLang и Microsoft, и их узаконили[50].
Гармонизация с Си
[править | править код]- В набор символов внесены остатки печатного ASCII
@$`
, которые могут пригодится впоследствии[51]. Ранее в Си23 добавили@$
, в первую очередь из-за EBCDIC — оба символа в разных диалектах кодировки на разных позициях[52]. - Выкинут
strtok
из автономной библиотеки вслед за Си[53], так как содержит внутреннее состояние. Большинство реализаций используют потоколокальные переменные, которые в автономной среде могут отсутствовать. - Переписан макрос
assert
, чтобы лучше поддерживались шаблоны и многомерная индексация, коих просто не существовало на момент появления препроцессора Си[54]. - Новые библиотеки Си23
stdbit.h
иstdckdint.h
, без Си++-аналогов<cstdbit/cstdckint>
[55].
Библиотека
[править | править код]Разные изменения в библиотеке
[править | править код]- Простейшая[к 1] библиотека идентификации кодировки исполнения[56].
- Получение системного дескриптора из
fstream
[57]. Может использоваться в высоконадёжном программировании, когда надо гарантированно записать данные на диск[58]. - Поддержка отладчика. Новый заголовочный файл
<debugging>
с тремя функциями:breakpoint()
,breakpoint_if_debugging()
,bool is_debugger_present()
[59]. - Теперь объект
ignore
применим не только вtie
:std::ignore = foo();
[60].
Автономная библиотека
[править | править код]Автономная (freestanding) библиотека не полагается на системные вызовы (даже выделение памяти), выброс исключений (требует серьёзной работы со стеком), может быть написана даже на чистом Си++ и потому полностью кроссплатформенна.
- Возможен (не обязателен)
operator new
, возвращающийnullptr
, приводящий к системной аварии или делающий что угодно по желанию реализатора. Добавлен макрос__cpp_lib_has_default_operator_new
, проверяющий, возможно ли выделение памяти — например, вместо динамического std::vector могут использоваться массивы ограниченного размера[61]. - Множество функций Си, включая строковые и математические, а также
<charconv>
иchar_traits
[62]. algorithm, array, optional, variant, string_view
[63]. Переписаны монадные функцииoptional
так, чтобы не ссылались на неавтономный (выбрасывающий исключения)value
.expected, span, mdspan
[64].
Новые constexpr
[править | править код]- Устойчивая сортировка[65].
consteval bool is_within_lifetime(&union_.field)
— «волшебная» (реализованная внутри компилятора) функция, проверяющая, держит ли union то или иное поле[66]. Типunion
при компиляции изначально (с Си++11) помеченный на манерvariant
, Си++20 позволил менять активное поле при компиляции, а доступ к другому полю отключаетconstexpr
. Используется для экстремальной оптимизации по памяти с сохранением константности — например, для однобайтовогоoptional<bool>
.- Больше математических функций, включая комплексные[67].
- Библиотека неинициализированной памяти, в constexpr-контексте или ничего не делающая, или проводящая простое присваивание[68][69].
atomic
,atomic_ref
[70].
Перевод данных в строку и наоборот
[править | править код]from_chars_result
получилoperator bool
[71] — проверку кода ошибки.to_string
для дробных выдаёт то же, что иformat("{}", x)
. А он, в свою очередь, то же, чтоto_chars
— в компактном точном нелокализованном виде[58][к 2]. Ранее он был унифицирован сprintf("%f", x)
, то есть обращался к глобальной локали (ненадёжно, да и вычисление нужных параметров локали затратно)[58] и плохо работал со слишком большими/малыми числами[72]. Это нарушение совместимости, ноto_string
значительно реже других методов перевода чисел в строку. Проверив случайные 100 вызовов, авторы обнаружили, что только семь из них дробные, в одном явная ошибка — запись в INI в локализованном виде, а остальные используются для отладки.stringstream
можно инициализировать строкамиstring_view
[73].- То же самое с
bitset
[74]. string + string_view
[75]. Изначально в операции отказали из-за особенностей архитектуры LLVM — всё, что можно, она исполняет «лениво», иappend
точками следования фиксирует, где исполнять, а сложение в большом выражении может выйти за время жизниstring_view
. Так что целых пять редакций — это попытка найти наиболее удачную реализацию.
format
(Си++20)
[править | править код]- Унифицировано форматирование указателей[76].
- Параметры ширины теперь также проверяются при компиляции[77].
- Форматирование строк, заранее не известных:
std::vformat(str, std::make_format_args(path.string()));
→std::format(std::runtime_format(str), path.string());
. Первое предназначено для писателей своих обёрток над форматированием вродеdoLog(str, args...)
, а не для конечных пользователей, и в пользовательском коде опасно: make_format_args содержит string_view, и если его вытащить в отдельную переменную, string_view будет жить дольше, чем временная строка. Для надёжности тонкая обёртка runtime_format_string принимается только по временной ссылке[78]. - В само́м
make_format_args
избавились от std::forward и временных объектов, делая форматирование более устойчивым к висячим ссылкам[79]. - Серьёзная ошибка, ранее случившаяся в fmt (прообразе format): кодовые единицы char, будучи отформатированы как числа или с «широкой» форматной строкой, выдавали зависящий от реализации вид[80]. Теперь char, отформатированный как число, будет unsigned; отформатированный как символ в широком контексте — символом с кодом 0…255.
- Форматирование
path
[81].
print
(Си++23)
[править | править код]println()
без параметров[82].print
может захватывать или не захватывать мьютекс консоли в зависимости от того, как происходит преобразование: преобразовать в строку целиком, потом вывести (например, для чисел), или параллельно преобразование-вывод (например, для массивов)[83].
- Добавлена
copyable_function
, построенная по принципу новойmove_only_function
(Си++23) и значительно более лёгкая[к 1], чемfunction
(Си++11). Последнюю всё-таки решили не запрещать[84]. - Добавлена совсем лёгкая
function_ref
, не инкапсулирующая вызываемый объект, а просто ссылающаяся на него[85]. Может использоваться для callback’ов, если основная функция тяжёлая и не хочется делать её шаблонной. Std::function (Си++11) тоже годится на эту роль, но он один из самых тяжёлых типов STL. Класс писали своими силами: в заявке приведены шесть реализаций, некоторые на Си++14, и три из них называлисьfunction_ref
. - Добавлен облегчённый шаблонный карринг через
bind_front
, если вызываемый объект (например, слот Qt) вычисляется раз и навсегда при компиляции[86]. - This-параметры из Си++23 позволили внести одну из перегрузок
visit
внутрьvariant
[87].
std::is_virtual_base_of
— важно при преобразовании указателей из типа в тип[88]. Приведён пример: в зависимости от того, виртуальный целевой указатель или нет,weak_ptr
переносится из типа в тип через сильный указатель или напрямую.- Объект
monostate
продублирован в<utility>
[89].
Хранение данных
[править | править код]- Добавлен
hash
для календарных типов[90]. - Добавлен
weak_ptr.owner_hash
и несколько других подобных функций[91]. - Закончен разнородный поиск в
[unordered_]set/map
: добавлены шаблонныеinsert
,insert_or_assign
,try_emplace
,operator[]
,bucket
[92]. Разнородный поиск начат в Си++14, и позволяет хранить с «тяжёлыми» ключами (string), а искать по «лёгким» (string_view или дажеconst char*
). Программист сам включает разнородный поиск (полем-типомCompareObject::is_transparent
) и задаёт набор допустимых ключей. - Операции сравнения для
reference_wrapper
[93]. - Возможность писать
std::find(v.begin(), v.end(), {3, 4});
[94]. Для этого всего лишь в шаблоны типаtemplate<class T, class Allocator, class U>
добавилиclass U=T
, которое работает, когда тип ключа определить невозможно.
inplace_vector
— простейший массив переменной длины
[править | править код]Массив переменной, но ограниченной длины, основанный на обычном массиве[95]. Этот контейнер часто пишут собственными силами — скажем, boost::static_vector<T, Capacity>
. Нужен, если даже обычный вектор слишком тяжёлый, или менеджер памяти недоступен (в автономной/безопасной среде, на очень ограниченных машинах). Constexpr, если внутренний тип тривиальный. Тривиально копируемый, если внутренний тип тривиально копируемый.
Частично автономный: часть функций при переполнении массива выбрасывает исключения. Но такие структуры любят в ограниченных средах, безопасном и системном программировании[96], где исключениями пользоваться не принято, так что есть функции вроде try_emplace_back
.
indirect
и polymorphic
— аналоги unique_ptr
[править | править код]Представляют собой указатели единоличного доступа. Семантически это объекты-значения, с такими отличиями от старого unique_ptr
:
- есть конструктор копирования, копирующий объект;
- const-доступ делает константным и объект;
- для удобства могут и не содержать объекта, и для этого есть функция, именуемая
valueless_after_move
, но эта семантика не поощряется; - может применяться оптимизация малых буферов.
Разница только в том, что indirect
поддерживает только свой тип (и годится, например, для идиомы pimpl), а polymorphic
— любой производный, и потому «под капотом» содержит инфраструктуру для подбора нужного конструктора копирования[97].
Диапазоны и другие представления данных
[править | править код]- Переписан
projected
(внутренний тип библиотеки диапазонов), лучше работающий с указателями на недоопределённые классы (class Opaque;
). Многие из функций диапазонов не работали там, где работал «голый» STL[98]. - Комплексным числам добавлено
get<0>
и<1>
, как обычным кортежам (tuples)[99]. basic_const_iterator
можно получить из не константного собрата[100].views::concat
[101].ranges::generate_random
[102] — стандартная версия простейшая, но авторы библиотек могут добавлять к генераторам/распределениям нестандартные функции, чтобы получать сразу много случайных чисел. Какие именно — стандарта пока нет.- Объекту
std::optional
даны итератор,begin
иend
— то есть он тоже стал диапазоном[103]. - Выкинуто
invocable<F&, iter_common_reference_t>
из многих концепций, связанных с итераторами, что позволило итераторы-заместители (vector<bool>
)[104]. views::cache_latest
[105].
span
(Си++20) и mdspan
(Си++23)
[править | править код]- Функция
submdspan
, производящая слайсинг многомерных массивов. На выходе получаетсяmdspan
(Си++23), возможно, с нестандартным типом внутри[106]. - Конструктор
span(initalizer_list)
, не требующий промежуточного объекта вроде массива[107]. span.at(i)
, выкидывающий аварию[108].mdspan
с излишним выравниванием[109].- Впоследствии сделали объект для излишнего выравнивания —
aligned_acccessor
[110].
- Впоследствии сделали объект для излишнего выравнивания —
- Улучшено угадывание статических (устанавливающихся при компиляции) габаритов
mdspan
, если таковые имеются[111]. std::mdspan<float, std::dextents<2>> a;
— не столько для краткости, сколько для угадывания шаблонных параметров:mdspan a(storage.data(), height, width);
[112].
Параллельное программирование
[править | править код]Атомарный API
[править | править код]atomic_fetch_min/max
— вычисление минимума/максимума атомарной переменной и обычной, и запись полученного обратно в атомарную[113].atomic_ref
может ссылаться на cv-объект. Предполагаемое назначение — объект в системной памяти и у него семантикаvolatile
, а для доступа между потоками одной программы нужен atomic[114].atomic_ref
может давать указатель на неатомарный объект[97]. Заявленные задачи: старый API наvolatile
, отход от атомарного доступа к неатомарному, атомарный доступ к полю объекта, а не ко всему объекту вместе.
Примитив неблокирующей синхронизации. Объект хранится в динамической памяти. Как только этот объект изменили, создают новый такой же, а старый, когда можно, удаляют[115].
// Было — блокирующая версия
Data* data_;
std::shared_mutex m_;
template <typename Func>
auto reader_op(Func fn) {
std::shared_lock<std::shared_mutex> l(m_);
Data* p = data_;
return fn(p);
}
void update(Data* newdata) {
Data* olddata;
{ std::unique_lock<std::shared_mutex> wlock(m_);
olddata = std::exchange(data_, newdata);
}
delete olddata;
}
// Стало — не блокируются только читатели
std::atomic<Data*> data_;
template <typename Func>
auto reader_op(Func fn) {
std::scoped_lock l(std::rcu_default_domain());
Data* p = data_;
return fn(p);
}
void update(Data* newdata) {
Data* olddata = data_.exchange(newdata);
std::rcu_synchronize();
delete olddata;
}
Главный недостаток идиомы read-copy-update в данном исполнении — не ждут только читатели, писатель может надолго «зависать». Это «зависание» означает, что другие читатели работают и держат объект, но не всегда допустимо.
Hazard pointer дополнительно следит, какие потоки пользуются тем или иным объектом, и как только объект перестаёт использоваться, он исчезает[116].
Идиома похожа на подсчёт ссылок, но подсчитывает только локальные ссылки из функций доступа — а не глобальные ссылки между объектами. Это позволяет циклические ссылки без слежения, чей «ранг» выше (от «контейнеров» к «содержимому» — shared_ptr
, в прочие стороны — weak_ptr
), а также без присущего shared/weak_ptr
управляющего объекта, исчезающего, когда исчезнет последний слабый указатель.
Система сделана беспрепятственной по записи ценой повышенного расхода памяти: read-copy-update хранит одно поколение старых данных, а hazard pointer — сколько угодно[58].
Поскольку G++ всё ещё держит совместимость двоичных интерфейсов, на будущие дополнения оставили 4/8 байтов на объект.
- (Старая блокирующая версия — та же)
// Стало — не блокируется и писатель
struct Data : std::hazard_pointer_obj_base<Data> {}
std::atomic<Data*> pdata_;
template <typename Func>
auto reader_op(Func userFn) {
std::hazard_pointer h = std::make_hazard_pointer();
Data* p = h.protect(pdata_);
return userFn(p);
}
void writer(Data* newdata) {
Data* old = pdata_.exchange(newdata);
old->retire();
}
Фреймворк асинхронно-параллельного исполнения
[править | править код]Предполагается, что немалые части этой библиотеки будут написаны не на Си++. Два главных объекта — планировщик (scheduler) и задача на исполнение (sender), оба — концепции (sender auto
). Для тех, кто сам пишет планировщики, есть объект receiver для этой же задачи[117].
using namespace std::execution;
scheduler auto sch = thread_pool.scheduler();
sender auto begin = schedule(sch);
sender auto hi = then(begin, []{
std::cout << "Hello world! Have an int.";
return 13;
});
sender auto add_42 = then(hi, [](int arg) { return arg + 42; });
auto [i] = this_thread::sync_wait(add_42).value();
Антон Полухин из Яндекса считает, что пока у этой системы есть недостатки: она устроена на шаблонах и концепциях (нет единого полиморфного объекта для передачи между библиотеками), и крайняя низкоуровневость[118].
В ноябре 2024 добавили объекты prop
и env
[119].
Математика
[править | править код]- В библиотеку рациональных чисел (Си++11) добавлены новые приставки СИ ронна-, ронто-, кветта-, квекто-[120].
Арифметика с насыщением (упором в край)
[править | править код]Стандартная работа беззнаковых типов — арифметика остатков: при переходе через значение превращается в 0. Знаковые — зависят от реализации. Но это не всегда нужно: например, может означать «сколько угодно» и прибавление к нему единицы должно оставлять . Никакой защиты от дурака нет. Поддерживаются четыре арифметических действия и преобразование типов. Деление с упором div_sat
при делении на ноль перестаёт быть константным[121].
# include <numeric>
// Считаем, что у нас 8-битный char и отрицательные в дополнительном коде
int x1 = add_sat(3, 4); // 7
int x2 = sub_sat(INT_MIN, 1); // INT_MIN
unsigned char x3 = add_sat(255, 4); // 3!! — работа в int и преобразование 259 → 3
unsigned char x4 = add_sat<unsigned char>(255, 4); // 255
unsigned char x5 = add_sat(252, x3); // Ошибка, нет нужной перегрузки
unsigned char x6 = add_sat<unsigned char>(251, x2); // 251!! — преобразование INT_MIN → 0
unsigned char x7 = saturate_cast<unsigned char>(-5); // 0
Заполненная линейная алгебра
[править | править код]Добавились BLAS-подобные алгоритмы линейной алгебры для заполненных (большей частью ненулевых) векторов и матриц[122]. Мотивация[122]:
- Комитет Си++ сам поставил линейную алгебру приоритетом.
- Си++ — стандартная платформа для наукоёмкого ПО, которому линейная алгебра более чем нужна.
- Это как сортировка массива: примитивные алгоритмы медленные, а самые быстрые реализации можно получить аппаратно-специфичными улучшениями.
- В стандарте Си++ и так много разной математики — и умножение матриц не менее важно, чем функции Бесселя.
- BLAS — известный стандарт линейной алгебры, мало менявшийся с годами.
- Это такой же путь к интеграции в Си++ сторонних стандартов, как Юникод (идёт работа) и часовые пояса.
Конструкция полностью шаблонная и на mdspan
. Преимущества перед стандартным BLAS:
- Работают любые типы, в том числе смешанные (данные в float, расчёт в double), а не только четыре стандартных BLAS’овских.
- Можно оптимизировать работу с матрицами небольших жёстко заданных габаритов — например, через SIMD.
- С небольшими изменениями возможно будет запустить целый пакет заданий (например, для машинного обучения).
Пока вне рассмотрения: расширенные функции BLAS/LAPACK, разреженная алгебра, расчёты повышенной точности, тензоры («матрицы» с тремя и более измерениями), параллельная работа, перегрузка операций ±. Последняя — из-за неоднозначности (есть несколько типов умножения векторов), данные могут быть в одном типе, а работа в другом, и из-за больших объёмов памяти и многоступенчатых расчётов промежуточные буфера часто используются повторно.
Добавлены[122]:
- Простейшие операции с матрицами вроде сложения
- Поиск, как надо повернуть вектор в 2D, чтобы одна из координат равнялась нулю (поворот Гивенса)
- Разные виды норм векторов и матриц
- Операции y := Ax, y := Ay, z := y + Ax для матриц общего вида, а также симметричных/эрмитовых/треугольных
- Операции A:=A + xyᵀ + yxᵀ, A:=A + αxxᵀ для симметричных/эрмитовых матриц (для эрмитовых матриц — вместо транспонирования соответственно эрмитово сопряжение)
- Операции A := xyᵀ, C := BA, C:=E + BA для матриц общего вида
- Операции C := BA, C := AC, C := CA, C:=E + BA для симметричных/эрмитовых/треугольных матриц
- Операция с симметричной/эрмитовой матрицей C :=C + αAAᵀ (матрица C была симметричной/эрмитовой и в результате ею останется, матрица A общего вида)
- Операция с симметричной/эрмитовой матрицей C:=C + ABᵀ + BAᵀ
- Решение треугольной СЛАУ, а также серии таких СЛАУ с общей матрицей
Нет даже решения заполненных СЛАУ. Вот одна из стандартных функций — решение треугольной СЛАУ на месте.
template<in-matrix InMat,
class Triangle,
class DiagonalStorage,
inout-vector InOutVec>
void triangular_matrix_vector_solve(
InMat A,
Triangle t,
DiagonalStorage d,
InOutVec b);
Здесь пустой тип-тэг Triangle показывает, каким треугольником собрана матрица, верхним или нижним. Аналогичный тэг DiagonalStorage — что представляет собой диагональ матрицы A: явные значения или неявные единицы. В векторе b изначально правая часть системы, в результате расчёта будет решение.
Семейство инкрементальных генераторов псевдослучайных чисел Philox
[править | править код]В параллельных расчётах сложно получить псевдослучайность: если брать несколько независимых генераторов (multistream approach), то чем их инициализировать? Можно также брать 2-е, 12-е, 22-е число (substream approach)[123], но арифметический генератор потребует 10 пусков на каждое число. В таких случаях используют специальные инкрементальные (основанные на счётчике) генераторы псевдослучайных чисел — к счётчику (единицы машинных слов) прибавляется 1, затем обрабатывается очень слабым шифром[124]. Потоки либо получают каждый по генератору с далёкими друг от друга значениями счётчика[124] в уверенности, что последовательности не пересекутся (multistream approach), либо берут 2-е, 12-е, 22-е число без потери производительности (substream approach)[123].
В Си++ добавлено семейство инкрементальных генераторов Philox (2011)[125], и две специализации philox4x32
и philox4x64
. Поведение каждой жёстко заспецифицировано: 10 000-й запуск версии 4×32 даст число 1 955 073 260. Семейство широко распространено и независимо реализовано у NumPy[124], nVidia, AMD, Intel, Microsoft…
Поддержка SIMD
[править | править код]Сложная долго разрабатывавшаяся библиотека[126]. Пример:
float * addr = ...;
void f(std::simd<double>x ) {
x.copy_to(addr, std::simd_flag_convert |
std::simd_flag_overaligned<16 >);
}
Ожидаются, но не одобрены
[править | править код]- Гармонизация с Си:
#embed
— инициализация массива данных двоичным файлом[127], прошла в Си23.
- Примитивы хранения данных:
- Улей — специализированный менеджер памяти для однотипных данных, используемый в играх и скоростной торговле. Никогда не перемещает, объект вставляется в случайное место, относительно быстры операции «проход», «добавление» и «удаление»[128].
path_view
, аналогstring_view
для путей[129]. По фактуvariant
, способный ссылаться без хранения на пути разных форматов и оперативно перекодировать в системный вид —rendered_path
, буфер достаточно больших размеров с возможностью запросить ещё больше, выделив память.
- Многозадачность:
- Параллельные очереди[130].
- «Волокна», элементы стековой кооперативной многозадачности[131]. Сопрограммы Си++20 бесстековые, то есть могут использоваться в любой среде, где есть setjmp/longjmp и выделение памяти (в автономной нет даже их).
- Прочее:
Будут неизвестно когда
[править | править код]Ожидается добавление дополнительных важных функций, однако пока не ясно, будут ли они готовы к сроку Си++26[134].
- Библиотечная поддержка сопрограмм (языковая есть в Си++20)
- Сеть — не удалось сделать модульный подход
- Контрактное программирование — уточнение условий на параметры функций
- Некое pattern matching — возможно, используя ключевое слово
inspect
, аналогswitch
, действующий даже на разные объектные подтипы и разные шаблоны строк[135]
Комментарии
[править | править код]- ↑ 1 2 Здесь и далее «лёгкий/тяжёлый» — по системным ресурсам (процессорному коду, расходу памяти и т. д.), «простой/сложный» — по работе программиста, «простейший» — по функциональности.
- ↑ Компактный — выбирает простой или стандартный вид в зависимости от того, что короче. Точный — производит достаточно цифр, чтобы обратное преобразование вернуло ту же дробь до бита. Нелокализованный — набор цифр всегда ASCII, знак отрицательного числа дефис-минус, разделитель дроби точка, разделителя тысяч нет.
Примечания
[править | править код]- ↑ Five Awesome C++ Papers for the H1 2023 — C++26, Varna and More — C++ Stories . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ 1 2 Trip report: Autumn ISO C++ standards meeting (Kona, HI, USA) – Sutter’s Mill . Дата обращения: 16 ноября 2023. Архивировано 16 ноября 2023 года.
- ↑ https://isocpp.org/files/papers/N4961.pdf
- ↑ Источник . Дата обращения: 30 июня 2024. Архивировано 12 августа 2024 года.
- ↑ Upcoming Meetings, Past Meetings : Standard C . Дата обращения: 6 марта 2024. Архивировано 7 сентября 2020 года.
- ↑ 1 2 P3176R0: The Oxford variadic comma . Дата обращения: 25 ноября 2024. Архивировано 30 ноября 2024 года.
- ↑ Источник . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Disallow Binding a Returned Glvalue to a Temporary
- ↑ 1 2 Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 13 сентября 2024. Архивировано 1 сентября 2024 года.
- ↑ Источник . Дата обращения: 25 ноября 2024. Архивировано 20 ноября 2024 года.
- ↑ Erroneous behaviour for uninitialized reads . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ P3247R2: Deprecate the notion of trivial types . Дата обращения: 25 ноября 2024. Архивировано 1 декабря 2024 года.
- ↑ Источник . Дата обращения: 29 ноября 2023. Архивировано 15 ноября 2023 года.
- ↑ Источник . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Источник . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Remove Deprecated strstreams From C++26 . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ std::wstring_convert — cppreference.com . Дата обращения: 23 марта 2024. Архивировано 9 марта 2024 года.
- ↑ Источник . Дата обращения: 24 июня 2024. Архивировано 24 июня 2024 года.
- ↑ https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2869r3.pdf
- ↑ Источник . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ P2308R0: Template parameter initialization . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Источник . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Structured binding declaration as a _condition_ - HackMD . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ What’s new in C++26 (part 1) . Дата обращения: 19 ноября 2024. Архивировано 15 ноября 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 29 августа 2023. Архивировано 29 августа 2023 года.
- ↑ Источник . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Источник . Дата обращения: 2 июля 2024. Архивировано 5 мая 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ 1 2 Trip report: Summer ISO C++ standards meeting (Varna, Bulgaria) — Sutter’s Mill . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ constexpr placement new . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ Источник . Дата обращения: 25 ноября 2024. Архивировано 20 ноября 2024 года.
- ↑ D3068R5: Allowing exception throwing in constant-evaluation . Дата обращения: 25 ноября 2024. Архивировано 27 ноября 2024 года.
- ↑ Источник . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ P2573R2: = delete(«should have a reason») . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Structured Bindings can introduce a Pack . Дата обращения: 25 ноября 2024. Архивировано 1 декабря 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2752R2: Static storage for braced initializers . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ A new specification for std::generate_canonical . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Clarifying rules for brace elision in aggregate initialization . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ P3034R1: Module Declarations Shouldn’t be Macros . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ P2809R3: Trivial infinite loops are not Undefined Behavior . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Remove nodiscard annotations from the standard library specification . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ Источник . Дата обращения: 8 августа 2024. Архивировано 8 августа 2024 года.
- ↑ Источник . Дата обращения: 25 ноября 2024. Архивировано 30 ноября 2024 года.
- ↑ https://isocpp.org/files/papers/P3379R1.html
- ↑ Retiring niebloids
- ↑ Add @, \$, and \` to the basic character set . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ N 2701: @ and $ in source and execution character set . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2937R0: Freestanding: Remove
strtok
. Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года. - ↑ Make assert() macro user friendly for C and C . Дата обращения: 17 ноября 2023. Архивировано 17 ноября 2023 года.
- ↑ P3370R1: Add new library headers from C23 . Дата обращения: 25 ноября 2024. Архивировано 20 ноября 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Native handles and file streams . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ 1 2 3 4 Первые новинки C++26: итоги летней встречи ISO / Хабр . Дата обращения: 14 сентября 2023. Архивировано 5 сентября 2023 года.
- ↑ Debugging Support . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Make std::ignore a first-class object . Дата обращения: 30 июня 2024. Архивировано 26 июня 2024 года.
- ↑ https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2013r5.html Архивная копия от 28 июля 2023 на Wayback Machine.
- ↑ P2338R4: Freestanding Library: Character primitives and the C library . Дата обращения: 8 августа 2023. Архивировано 10 августа 2023 года.
- ↑ P2407R5: Freestanding Library: Partial Classes . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ P2833R2: Freestanding Library: inout expected span . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Checking if a union alternative is active . Дата обращения: 31 июля 2023. Архивировано 21 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 30 июля 2023 года.
- ↑ P3369R0: constexpr for uninitialized_default_construct . Дата обращения: 25 ноября 2024. Архивировано 20 ноября 2024 года.
- ↑ P3508R0: Wording for "constexpr for specialized memory algorithms" . Дата обращения: 25 ноября 2024. Архивировано 2 декабря 2024 года.
- ↑ P3309R3: constexpr atomic<T> and atomic_ref<T> . Дата обращения: 25 ноября 2024. Архивировано 3 декабря 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2587R3:
to_string
or notto_string
. Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года. - ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 21 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 21 июля 2023 года.
- ↑ P2591R4: Concatenation of strings and string views . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Type-checking format args . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2918R1: Runtime format strings II . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ P2905R1: Runtime format strings . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ P2909R4: Fix formatting of code units as integers
(Dude, where’s my char?) . Дата обращения: 23 марта 2024. Архивировано 1 марта 2024 года. - ↑ P2845R6: Formatting of std::filesystem::path . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Источник . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ P3107R3: Permit an efficient implementation of std::print . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 21 июля 2023 года.
- ↑ function_ref: a type-erased callable reference — HackMD . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Bind front and back to NTTP callables — HackMD . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Member visit . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2985R0: A type trait for detecting virtual base classes . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ Источник . Дата обращения: 25 ноября 2024. Архивировано 1 декабря 2024 года.
- ↑ P2592R3: Hashing support for std::chrono value classes . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P1901R2 — Enabling the Use of weak_ptr as Keys in Unordered Associative Containers . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2363R5: Extending associative containers with the remaining heterogeneous overloads . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Comparisons for reference_wrapper . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ P2248R8: Enabling list-initialization for algorithms . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ `inplace_vector` - HackMD . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ Новости РГ21 — группы по стандартизации C++ | Антон Полухин, Яндекс - YouTube
- ↑ 1 2 Источник . Дата обращения: 25 ноября 2024. Архивировано 27 ноября 2024 года.
- ↑ P2538R1: ADL-proof std::projected . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 14 ноября 2023. Архивировано 10 октября 2023 года.
- ↑ `std::basic_const_iterator` should follow its underlying type’s convertibility . Дата обращения: 14 ноября 2023. Архивировано 15 ноября 2023 года.
- ↑ `views::concat` . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Источник . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ Give std::optional range support - HackMD . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ Removing the common reference requirement from the indirectly invocable concepts . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ views::cache_latest . Дата обращения: 25 ноября 2024. Архивировано 29 ноября 2024 года.
- ↑ Submdspan . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2447R4:
std::span
over an initializer list . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года. - ↑ span.at() — HackMD . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ Padded mdspan layouts . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ aligned_accessor: An mdspan accessor expressing pointer over-alignment
- ↑ Better
mdspan
's CTAD . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года. - ↑ dextents Index Type Parameter . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ Источник . Дата обращения: 23 марта 2024. Архивировано 23 марта 2024 года.
- ↑ cv-qualified types in atomic and atomic_ref
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P2300R10: `std::execution` . Дата обращения: 1 июля 2024. Архивировано 1 июля 2024 года.
- ↑ Новости РГ21 — группы по стандартизации C++ | Антон Полухин, Яндекс - YouTube
- ↑ A Utility for Creating Execution Environments . Дата обращения: 25 ноября 2024. Архивировано 26 ноября 2024 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ P0543R3: Saturation arithmetic . Дата обращения: 14 ноября 2023. Архивировано 14 ноября 2023 года.
- ↑ 1 2 3 A free function linear algebra interface based on the BLAS . Дата обращения: 14 ноября 2023. Архивировано 5 ноября 2023 года.
- ↑ 1 2 Источник . Дата обращения: 13 сентября 2024. Архивировано 15 сентября 2024 года.
- ↑ 1 2 3 Philox counter-based RNG — NumPy v2.1 Manual . Дата обращения: 13 сентября 2024. Архивировано 13 сентября 2024 года.
- ↑ Источник . Дата обращения: 30 июня 2024. Архивировано 30 июня 2024 года.
- ↑ https://isocpp.org/files/papers/P1928R15.pdf
- ↑ C++23 — финал, C++26 — начало / Хабр . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Introduction of std::hive to the standard library . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 21 июля 2023 года.
- ↑ C++ Concurrent Queues . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ Источник . Дата обращения: 31 июля 2023. Архивировано 24 сентября 2023 года.
- ↑ A Plan for C++23 Ranges . Дата обращения: 9 августа 2023. Архивировано 11 августа 2023 года.
- ↑ `std::constexpr_v` . Дата обращения: 31 июля 2023. Архивировано 31 июля 2023 года.
- ↑ To boldly suggest an overall plan for C++26 . Дата обращения: 8 августа 2023. Архивировано 10 августа 2023 года.
- ↑ Источник . Дата обращения: 8 августа 2023. Архивировано 10 августа 2023 года.