LINUX.ORG.RU

Утверждён стандарт C++26

 ,


3

8

Комитет ISO по стандартизации языка C++ утвердил финальный вариант спецификации, образующей международный стандарт «C++26». Представленные в спецификации возможности частично уже поддерживаются в компиляторах GCC (gnu.org), Clang и Microsoft Visual C++. Поддерживающие C++26 стандартные библиотеки реализованы в рамках проекта Boost.

В следующие два месяца утверждённая спецификация будет находиться на стадии подготовки документа к публикации, на которой будет проведена работа по редакторской правке орфографических ошибок и опечаток. В начале ноября результирующий вариант документа будет направлен в ISO для публикации под формальным именем ISO/IEC 14882:2026.

Основные особенности C++26:

  • Реализованы элементы контрактного программирования (Contracts), позволяющие определять формальные спецификации интерфейсов при помощи трёх новых операторов: pre (предусловие), post (постусловие) и contract_assert (проверка утверждения). Оператор pre определяет предварительные условия, которые должны быть выполнены перед вызовом (проверка входных данных); post – условия, которые должны соблюдаться после выполнения (требования к выходным данным); contract_assert – условия возникновения исключений. Возможность появится в GCC 16.
       int f(const int x)
          pre (x != 1) // требования ко входным данным
          post (r : r == x && r != 2) // требования к результату; r - значение с результатом
       {
          contract_assert (x != 3);
          return x;
       }
  • Добавлена поддержка рефлексии (Reflection), позволяющей отслеживать и модифицировать элементы программы на стадии компиляции. Добавлены новые операторы «^^ (open-std.org)» для получения метаинформации о грамматической конструкции и «[:…:]» для выполнения обратного преобразования. Для преобразования и обработки полученной в ходе инспектирования информации предложена библиотека std::meta и доступны такие возможности, как вычисления с константами. Поддержка рефлексии будет добавлена в GCC 16.
       constexpr int i = 42, j = 42;
    
       constexpr std::meta::info r = ^^i, s = ^^i;
       static_assert(r == r && r == s);
    
       static_assert(^^i != ^^j);  // 'i' и 'j' имеют различные значения.
       static_assert(constant_of(^^i) == constant_of(^^j));    // 'i' и 'j'  одинаковы
       static_assert(^^i != std::meta::reflect_constant(42));  // отличается от значения 42
  • Добавлен оператор «template for» для перебора элементов, таких как пакеты параметров, похожие на кортежи объекты и результаты рефлексии (метаобъекты), на этапе компиляции в стиле обычного цикла. При выполнении template for тело цикла раскрывается для каждого элемента и каждая итерация обрабатывается в отдельной области видимости, в которой меняющаяся в цикле переменная является константой. В контексте рефлексии template for может применяться для обхода свойств классов или перечислений. Возможность появится в GCC 16.
       void f() {
         template for (constexpr int I : std::array{1, 2, 3}) {
           static_assert(I < 4);
         }
       }
будет раскрыто в:
       void f() {
       {
           constexpr auto&& __range = std::array{1, 2, 3};
           constexpr auto __begin = __range.begin();
           constexpr auto __expansion-size = __range.end() - __begin; // 3
    
           {
             constexpr int I = *(__begin + 0);
             static_assert(I < 4);
           }
    
           {
             constexpr int I = *(__begin + 1);
             static_assert(I < 4);
           }
    
           {
             constexpr int I = *(__begin + 2);
             static_assert(I < 4);
           }
         }
       }
  • Добавлен фреймворк std::execution для асинхронного и параллельного выполнения кода. Предоставляются объекты scheduler, определяющий планировщик выполнения работ (поток, пул потоков, GPU, event loop), sender, определяющий выполняемую работу, и receiver – обработчик результата.
       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();
  • Добавлена библиотека std::simd для распараллеливания выполнения операций над данными при помощи наборов инструкций SIMD, таких как AVX-512 и NEON, с использованием стандартной системы типов C++.
        std::simd<float> a = {1.0f, 2.0f, 3.0f, 4.0f};
        std::simd<float> b = {5.0f, 6.0f, 7.0f, 8.0f};
    
        std::simd result = a + b;
  • Предложена реализация вектора (массива) переменного размера std::inplace_vector, размещаемого в стеке, размер которого определяется на этапе компиляции. API близок к std::vector, но элементы массива хранятся не в «куче», а внутри объекта.
       inplace_vector a(10);
       inplace_vector b(std::move(a));
       assert(a.size() == 10); 
  • Добавлена директива «#embed», предназначенная для встраивания в код бинарных ресурсов.
       const unsigned char icon_display_data[] = {
           #embed "art.png"
       };
  • Добавлена поддержка генерации и обработки исключений на этапе компиляции при ошибках в контексте constexpr.
       constexpr std::optional<unsigned> checked_divide(unsigned n, unsigned d) {
    	try {
    		return divide(n, d);
    	} catch (...) {
    		return std::nullopt;
    	}
       }
    
       constexpr date parse_date(std::string_view input) {
    	auto [correct, year, month, day] = ctre::match<"([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})">(input);
    	
    	if (!correct) {
    		throw incorrect_date{input};
    	}
    	
    	return build_date(year, month, day);
       }
  • Реализована структура данных std::hive для неупорядоченного хранения данных и обеспечения повторного использования памяти, освободившейся после удалённых элементов. Структура оптимизирована для нагрузок с высокой интенсивностью добавления и удаления элементов в произвольном порядке. В отличие от массивов, удаление элемента в std::hive не вызывает сдвига других элементов, а приводит к пометке удалённого элемента пустым с последующим заполнением освободившейся позиции при добавлении нового элемента.
  • Добавлена библиотека std::linalg c API для линейной алгебры, основанный на BLAS.
  • Добавлена поддержка механизма синхронизации Hazard pointer, позволяющего без выставления блокировок предотвратить освобождение памяти объектов, с которыми продолжается работа в других потоках. При удалении объекта, он лишь помечается удалённым, но занимаемая объектом память освобождается только когда все потоки снимут hazard-указатель, выставляемый во время работы с объектом.
  • Добавлена поддержка механизма синхронизации RCU (open-std.org) («read-copy update») – при операциях записи создаётся новый экземпляр объекта, а операции чтения не блокируются, а продолжают работать со старым экземпляром. После завершения изменения новый экземпляр становится активным и новые операции чтения уже производятся с ним, а старый экземпляр удаляется после завершения читающих его потоков.
  • Внесены изменения для усиления безопасности стандартной библиотеки, такие как проверки допустимых значений и выхода за границы буфера. Например, при доступе к элементу constexpr reference operator[](size_type idx) const; добавляется проверка условия idx < size().
  • Предоставлена возможность использования ключевого слова constexpr с разновидностью оператора new («placement new») для размещения объекта в заранее выделенной памяти во время компиляции.
  • Добавлена поддержка структурированных привязок («structured binding») в контексте constexpr, т. е. ссылки на константные выражения теперь сами могут быть константными выражениями. Поддержка реализована для массивов и простых структур.
       constexpr int arr[] = {1, 2};
       constexpr auto [x, y] = arr; 
  • В структурированные привязки добавлена возможность использования синтаксиса ... для указания пакетов (pack), захватывающих оставшееся число элементов из присваиваемой последовательности.
       auto [x,y,z] = f();         // в переменные  x, y, z будут записаны  три элемента, возвращённые f().
       auto [...xs] = f();         // в пакет xs будут записаны все элементы, возвращённые f().
       auto [x, ...rest] = f();    // В x будет записан первый элемент, а в rest - остальные.
       auto [x, y, ...rest] = f(); // В x будет записан первый элемент, в y - второй, а в rest - третий.
       auto [x, ...rest, z] = f(); // в x - первый, в rest - второй, в z - третий.
  • Добавлена поддержка «тривиальной перемещаемости» типов («trivial relocatability»), позволяющей оптимизировать перемещения объектов заданного типа через их клонирование в памяти без вызова конструкторов или деструкторов. Для классов реализованы свойства memberwise_trivially_relocatable и memberwise_replaceable, а для низкоуровневого перемещения одного или нескольких объектов добавлены функции trivially_relocate_at и trivially_relocate.
  • Реализована поддержка прикрепления функции main() к глобальному модулю и определения функции main() в именованных модулях.
  • Добавлен вариативный оператор friend (friend Ts...).
  • Реализованы атрибуты для структурированных привязок;
  • Добавлен синтаксис ‘= delete(«причина»)’.
  • В базовый набор символов включены «@», «$» и «`».
  • Предоставлена возможность применения структурированного связывания («structured binding») в качестве условия в операторах if и switch.
  • Добавлена возможность использования сразу нескольких переменных-заполнителей с именем _ в одной области видимости, например, теперь являются корректными конструкции:
        struct S {
          int _, _; 
        };
        void func() {
          int _, _;
        }
        void other() {
          int _; // ранее выводилось предупреждение в режиме -Wunused
        }
  • Предоставлена возможность использования строковых литералов в контексте, в котором они не используются для инициализации массива символов и не попадают в результирующий код, а применяются только во время компиляции для диагностических сообщений и препроцессинга, например, в качестве параметров директив и атрибутов _Pragma, asm, extern, static_assert, [[deprecated]] и [[nodiscard]].
  • Добавлены встроенные функции: __builtin_is_within_lifetime для проверки активности альтернативы в объединениях («union») и __builtin_is_virtual_base_of для проверки является ли базовый класс виртуальным.
  • Реализованы тривиальные бесконечные циклы без неопределенного поведения.
  • Обеспечен вывод ошибки при удалении указателя на неполный тип.
  • Объявлен устаревшим синтаксис определения вариативных параметров с многоточием без предшествующей запятой (например, когда указывается void e(int...) вместо void e(int, ...)).
  • Запрещено использование макросов для объявления модулей.
  • Переведено в разряд устаревших выполнение неявных преобразований перечисляемых значений в арифметических вычислениях.
       int main() {
          enum E1 { e };
          enum E2 { f };
          bool b = e <= 3.7; // устарело
          int k = f - e; // устарело
          int x = +f - e; // OK
       }
  • Прекращена поддержка прямого сравнения массивов.
       int arr1[5]; 
       int arr2[5]; 
       bool same = arr1 == arr2;

>>> Источник: OpenNET

★★★★★

Проверено: Dimez ()
Последнее исправление: dataman (всего исправлений: 1)

Добавлена поддержка механизма синхронизации Hazard pointer, позволяющего без выставления блокировок предотвратить освобождение памяти объектов, с которыми продолжается работа в других потоках. При удалении объекта, он лишь помечается удалённым, но занимаемая объектом память освобождается только когда все потоки снимут hazard-указатель, выставляемый во время работы с объектом.

Что, рефкаунтинг переизобрели? Чем это отличается от шаред поинтеров?

anonmyous ★★★
()
Ответ на: комментарий от v_0ver

Слава Богу я ушёл на Rust 4 года назад. Жаль только, что эту плюсовую херобору читать всё ещё приходится =(

Заменил шило на шилья, поздравляю.

dataman ★★★★★
() автор топика
Ответ на: комментарий от dataman

Заменил шило на шилья, поздравляю.

Может он при этом еще и поднял средний IQ в каждом из комньюнити ;)

eao197 ★★★★★
()
Ответ на: комментарий от v_0ver

Слава Богу я ушёл на Rust 4 года назад

эскобар.жпг

annulen ★★★★★
()
Ответ на: комментарий от unC0Rr

https://github.com/FractalFir/rustc_codegen_clr

Любопытно, но на промышленное решение не тянет. Во времена первых компиляторов C++ практически все были транспилерами, первым нативным, насколько я помню, был Zortech С++.

А основной Eiffel-компилятор от Eiffel Software, емнип, еще в 2007-ом как транспилер работал, генерировал из Eiffel-я чистый Си, потом этот Си собирал Си-шным компилятором. Не удивлюсь, если дело до сих пор так и обстоит.

eao197 ★★★★★
()

Эти разработчики С++ какие-то идиоты.

Передрали contracts из Ada/SPARK но до ума не довели.

Какой в них смысл, если элементарный IF делает тоже самое и даже лучше.

Люди просто уничтожают язык доводя его до безобразия. И все кто могут ищут убежища где угодно за пределами C++.

Особенно эта когда работающий код убивают переключением default версии, которые между собой не совместимы.

В лучших традициях саги python-2.7 to python-3

Слова Саттера про одну девченку - The whole new language.. - вырвать может.

Но зараза все на него завязано и тебе CUDA и все остальное.

Когда же он умрет?

lefsha
()
Последнее исправление: lefsha (всего исправлений: 1)
Ответ на: комментарий от eao197

Возможно, действия из категории: надо начать. Хотя, как вы же, емним, и сказали: сначала бы TS, который реализовать в «большой тройке», отработать, посмотреть, насколько хорошо, а потом с корректировками тащить в стандарт.

По мне, что сильно долгий период от C++03 до C++11 хреново, что фиксированные «спринты» по три года тоже так себе: фичи появляются непродуманные, сырые или незаконченные. Взять те же корутины… как я понимаю, в C++26 так и не завезли библиотечной поддержки?

hatred ★★★★
()
Последнее исправление: hatred (всего исправлений: 1)
Ответ на: комментарий от lesopilorama

эээээ первая реализация была буквально транспилером в си-сырцы

поэтому это продлилось не долго но родимые пятна в синтаксисе просвечивают

qulinxao3 ★☆
()
Ответ на: комментарий от eao197

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

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

что и приводит к «дырчатым» не ортогональностям — в малых дозах оно как раз таки нужно что бы не получалось у совсем apl и прочего среди людей простых малопонятного.

qulinxao3 ★☆
()
Ответ на: комментарий от hatred

фиксированные «спринты» по три года тоже так себе: фичи появляются непродуманные, сырые или незаконченные

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

eao197 ★★★★★
()
Ответ на: комментарий от qulinxao3

поэтому это продлилось не долго но родимые пятна в синтаксисе просвечивают

Как обычно, без пруфов.

lesopilorama
()
Ответ на: комментарий от unixnik

Странно, один чёрный, и то не видно.

Остальные заняты - местные лавки обносят

BydymTydym ★★
()
Ответ на: комментарий от hatred

Взять те же корутины… как я понимаю, в C++26 так и не завезли библиотечной поддержки?

У них же стеклесс корутины. Зачем им библиотечная поддержка?

anonmyous ★★★
()
Ответ на: комментарий от Somebody

наоборот - молодость! бОлее пОздний кОд - это как раз бОлее молодой! :о)

sunjob ★★★★★
()
Ответ на: комментарий от v_0ver

А пулить их кто будет?

Стеклесс корутины пулить? Разверните-ка мыслю.

anonmyous ★★★
()
Ответ на: комментарий от lefsha

If тоже самое не делает. Контракты управляются флагами компиляции. Они могут работать в режимах ignore где их физически нет в коде и в report

Reset ★★★★★
()
Ответ на: комментарий от anonmyous

У них же стеклесс корутины. Зачем им библиотечная поддержка?

Наверное братюня имел ввиду какое-то облегчённое использование корутин. Корутины из C++20 чтобы начать использовать, надо в дурке отсидеть. Там буквально низкоуровневые провода из компилятора торчат, к которым твоя задача прикрутить всё остальное. Не хватает

Coroutine bugaga() {
  auto a = co_await skotina(1);
  auto b = co_await dura(2);
  co_return co_await skototarnya(a + b);
}

std::coroutine::run(bugaga);
lesopilorama
()
Ответ на: комментарий от lesopilorama

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

Стеклесс корутины всегда так и выглядят. Ну, единственное, что типы для промисов приходилось руками писать. Вроде как, это маразм. Но в с++26 добавили std::execution, так что проблем уже не вижу.

anonmyous ★★★
()
Последнее исправление: anonmyous (всего исправлений: 1)
Ответ на: комментарий от Reset

Они могут работать в режимах ignore где их физически нет в коде и в report

И какой в них смысл тогда?

Вы точно так же можете сделать условную компиляцию в случае IF. Разницы ноль.

Но дело не в разнице. Дело в пользе! Пользы ноль.

Польза была бы если бы это было compile time поведение. Это как бы понятно зарание. Зачем забивать язык новыми никому не нужными выражениями?

Язык должен быть просто и лаконичен. Вот например F#.

Если придумать 100 тыс новых конструкций, то ими никто не будет пользоваться. И какой в этом смысл? Чтобы раздуть компилятор?

То что делают с C++ это тихий ужас.

lefsha
()
Ответ на: комментарий от anonmyous

Стеклесс корутины всегда так и выглядят. Ну, единственное, что типы для промисов приходилось руками писать. Вроде как, это маразм. Но в с++26 добавили std::execution, так что проблем уже не вижу.

Как они выглядят - это уже варианты. Выглядеть они могут супер няшно, а под капотом быть какие и есть сейчас. А могут никак не выглядеть, а торчать провода. Вот в C++20 они просто «никак не выглядят» - вам дали провода, а панель приборов сами припаивайте. А народ хочет готовую панель приборов.

lesopilorama
()
Ответ на: комментарий от lesopilorama

Я думаю что красивей/приятней это уже не C++-way. Скрыть под капотом провода - значит скрыть возможность тюнить что-то. А положить рядом опциональную красивую панель которая легко подключается к проводам - это уже излишество по философии std мира. Как, впрочем, и удобные string методы навроде как в QString.

water_closed
()
Ответ на: комментарий от water_closed

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

water_closed
()
Ответ на: комментарий от lesopilorama

Вот в C++20 они просто «никак не выглядят» - вам дали провода, а панель приборов сами припаивайте. А народ хочет готовую панель приборов.

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

anonmyous ★★★
()

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

SL_RU ★★★★
()

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

Очень не хватало рефлексии, но её текущая реализация - просто грусть

Контракты добавили, а stdlib даже на 10% не подготовлена к котрактам

SL_RU ★★★★
()
Ответ на: комментарий от lefsha

И какой в них смысл тогда?

Заменить assert, очевидно же. А старый assert не вписался в новые плюсы, т.к. стандартная либа переезжает в модуль (import std), а из него не могут торчать макросы, а старый assert он на макросах. Было бы странно писать такое:

import std;
include <cassert>

Если тебе нужно в компайл тайме, то возьми static_assert, в чём проблема?

kvpfs_2
()
Ответ на: комментарий от Beewek

Ну, тут палка о двух концах. После fmt использовать printf не очень хочется. Но, конечно, в некоторых жёстких условиях приходится.

AlexM ★★★★★
()
Ответ на: комментарий от anonmyous

Библиочечная поддержка как раз для примитивов.

Попробуй с тем, что сейчас есть, без Asio, написать асинхронный TCP клиент или сервер. А потом погляди как это делается с Asio. Станет понятнее.

Из того что есть, емнип, только std::generator завезли в C++23.

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

и ещё немало источников.

Именно это вкладывается у меня в понятие библиотечной поддержки. Пример:

  • завести nullptr, но забыть дать std::nullptr_t - примитивно, но необходимо
  • завести экзекуторы и прочие прелести параллельных алгоритмов, но не дать алгоритмов и ренжей, которые с этим экзекуторами работают.
  • дать концепты, но не дать ни одного концепта (тоже же можно самому писать)
  • дать constexpr/consteval, но не дать ни одной библиотечной функцнии с ними (тут в общем-то так и вышло, но худо-бедно решается)

Список аналогий можно продолжать.

hatred ★★★★
()
Ответ на: комментарий от anonmyous

Да не особо-то и есть. Нужно будет, конечно, поглядеть на stdexec: насколько он полно переедет в C++26 - вопрос.

hatred ★★★★
()
Последнее исправление: hatred (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.