actu-image
Software engineering PL - 06 lis 2026

Norma ISO C++26: dlaczego projekt standardu został odrzucony i jaka przyszłość czeka ten język?

W skrócie: Podczas historycznego głosowania zakończonego 22 października 2026 r. projekt roboczy standardu został odrzucony — C++26 zostało odrzucone przez krajowe jednostki normalizacyjne ISO (National Bodies). W samym centrum kontrowersji znalazła się integracja kontraktów (contracts) (P2900), ostro kwestionowana przez Bjarne Stroustrupa oraz kilku twórców kompilatorów ze względów bezpieczeństwa i dojrzałości technologicznej. To odrzucenie stawia pod presją harmonogram wydania C++26 i rodzi pytania o utrzymanie kluczowych funkcjonalności, takich jak refleksja statyczna (static reflection).

Ewolucja języka C++ przechodzi bezprecedensowy kryzys. Choć publikacja przyszłego standardu wydawała się na dobrej drodze, decyzja komitetów narodowych wywraca roadmapę standardu ISO do góry nogami. Nasze zespoły inżynierii oprogramowania szczegółowo analizują przyczyny, które doprowadziły do odrzucenia C++26, rozbieżności techniczne wokół programowania kontraktowego (Design by Contract) oraz scenariusze wyjścia z kryzysu.

Thibault Ricord-Marchal - Analiza odrzucenia C++26

Artykuł napisany przez

Thibault Ricord-Marchal

Inżynier Konsultant Software Engineering

Programista C++ i systemów embedded w MARGO, obecnie realizujący projekty dla BNP CIB. Z natury ciekawy świata, dzielę się tutaj moim monitoringiem technologicznym i analizą przypadku odrzucenia C++26 przez ISO oraz ewolucji języków programowania.

Draft C++26 odrzucony przez krajowe jednostki normalizacyjne

Po raz pierwszy w historii C++ krajowe jednostki normalizacyjne (National Bodies) odrzuciły ostateczny draft standardu. Powód: kontrakty, główna nowość C++26 mająca zapewnić rozwiązanie na poziomie języka (language-level) dla programowania zorientowanego na kontrakty i ostatecznie pogrzebać makro assert odziedziczone z języka C. Głosowanie, zamknięte 22 października 2026 r., przyniosło 13 głosów za, 9 przeciw i 12 wstrzymujących się. To daleko od wymaganej przez ISO większości dwóch trzecich głosów poparcia i dopuszczalnego maksimum jednej czwartej głosów negatywnych.

1. Kontrakty: wieloletnia ambicja C++

Kontrakty umożliwiają bezpośredni zapis w kodzie warunków, jakich funkcja oczekuje i jakie gwarantuje. Przyjęta propozycja (P2900) oferuje je w trzech formach: parę pre/post, reprezentującą odpowiednio warunki wstępne (preconditions) i warunki końcowe (postconditions) funkcji, umieszczaną przy jej deklaracji, oraz asercję contract_assert w ciele funkcji.

int racine(int x)
  pre (x >= 0)
  post (r : r >= 0);

Każdy kontrakt może być zignorowany (ignored), obserwowany (observed — naruszenie jest raportowane, wykonanie trwa dalej) lub egzekwowany (enforced — program zatrzymuje działanie). Wybór ten nie następuje w kodzie, lecz podczas kompilacji, zazwyczaj za pomocą odpowiedniej flagi. Globalny handler naruszeń (violation handler), z możliwością zastąpienia go przez aplikację, centralizuje obsługę błędów.

Ideą jest udostępnienie kontraktów kodowi wywołującemu (callerowi), który może je w razie potrzeby sprawdzić, a narzędzia analityczne zyskują do nich dostęp bez zagłębiania się w implementację funkcji. Historycznie kontrakty te opisywano w komentarzach, na przykład w formacie Doxygena /// @pre \p x >= 0, a następnie dodawano do wnętrza funkcji, potencjalnie z użyciem assert, co stwarzało ryzyko rozbieżności w czasie między dokumentacją a kodem.

Co więcej, kontrakty stanowiły gotowe rozwiązanie dla wzmocnienia biblioteki standardowej (STL hardening), na przykład poprzez dodanie pre(index < size()) do std::vector::operator[].

Koncepcja ta nie jest w C++ nowa — pierwsza propozycja pochodzi z 2004 roku, a pewna wersja kontraktów została już przyjęta dla C++20, po czym wycofano ją in extremis w 2019 roku. Komitet wystartował od zera z „minimalnym opłacalnym produktem” (MVP) przeznaczonym do późniejszej rozbudowy. Wersja ta została przyjęta przez komitet w lutym 2025 roku stosunkiem głosów 100 do 14.

2. Spór techniczny i proceduralny

Mniejszość w komitecie, skupiona przede wszystkim wokół Bjarne Stroustrupa oraz zespołów implementujących kompilatory z Microsoftu i EDG, nigdy nie zaakceptowała tej koncepcji. Nie uzyskawszy poparcia wewnątrz komitetu, zwróciła się bezpośrednio do krajowych jednostek normalizacyjnych. Kilka z nich, w tym francuski AFNOR, wnioskowało o wycofanie kontraktów już w 2025 roku. Dominują trzy obawy.

2.1 Brak gwarancji i zabetonowane zachowanie domyślne

Nic w C++26 nie gwarantuje nienaruszalności kontraktu z poziomu kodu źródłowego. Jedynie kompilacja decyduje o poziomie ich aktywacji, przez co kontrakt nie może zostać bezwzględnie wymuszony. Co więcej, poziomowi aktywacji brakuje ziarnistości (granularity): albo aktywuje się wszystkie, albo wyłącza wszystkie. Nie można zdefiniować np. kontraktów obowiązkowych obok kontraktów weryfikowanych wyłącznie w trybie debug.

Gorzej: funkcja inline skompilowana z różnymi ustawieniami w dwóch bibliotekach może utracić kontrolę podczas fazy linkowania (link phase), o czym nikt nie zostanie poinformowany.

Mechanizm etykiet („labels”), planowany na C++29 (P3400), naprawiłby część tych problemów, wprowadzając składnię pre, w której label pozwala na zastosowanie własnej strategii. Tyle że dotyczyłoby to wyłącznie tych, którzy z nich skorzystają: składnia skrócona, bez etykiety, zachowałaby swoje obecne zachowanie, gdyż nie dałoby się jej zmienić bez złamania kompatybilności wstecznej istniejącego kodu.

Zwolennicy odpowiadają, że te same problemy występują już przy assert, gdzie stanowi to nawet niezdefiniowane zachowanie (undefined behavior), a niewykonana kontrola to „nic gorszego niż brak jakiejkolwiek asercji”. Rodzi to jednak uzasadnione pytania — skoro dodaje się nową funkcjonalność do C++, celem powinno być wyciągnięcie wniosków z historycznych rozwiązań i uniknięcie powielania ich wad.

2.2 Niewystarczająca dojrzałość

Kontrakty zostały zaimplementowane w GCC i Clang, lecz doświadczenia wdrożeniowe ograniczyły się głównie do contract_assert. Warunki wstępne i końcowe w deklaracjach, stanowiące prawdziwą innowację, nie przeszły testów na dużą skalę.

Argument ten podnosi część przeciwników kontraktów, choć nie wszyscy. Należy przyznać, że brak dojrzałości jest również wadą statycznej refleksji czy std::execution, które mimo to także zostały włączone do standardu.

2.3 Zakwestionowany konsensus

W tym miejscu wchodzimy w kwestie czysto proceduralne. Kiedy wszystko przebiega pomyślnie, propozycja posuwa się naprzód poprzez kolejne głosowania i ankiety. Członkowie komitetu głosują na poziomach: SF (strong favor), F (favor), N (neutral), A (against) lub SA (strong against). Jeśli członek głosuje A lub SA, musi dołączyć do swojego głosu komentarz lub pytanie uzasadniające sprzeciw. Zwyczajowo (choć nieobowiązkowo) autorzy propozycji odpowiadają na te pytania, aby rozwiać wątpliwości lub skorygować wskazane błędy.

Przeciwnicy uważają, że projekt forsowano kolejnymi głosowaniami, rzadko odpowiadając na zgłaszane zastrzeżenia. Były przewodniczący grupy badawczej, John Spicer, opublikował nawet mea culpa, w którym przyznaje, że popierał tempo prac wykluczające obiekcje kluczowych członków, w tym autorów kompilatorów z Microsoftu i EDG. Zwolennicy kontraktów przypominają z kolei, że każde zastrzeżenie było przedmiotem debat na wielu spotkaniach, a trwały sprzeciw nie oznacza prawa weta. W rzeczywistości panuje poczucie, że dyskusje nie przyniosły rozwiązań zgłoszonych problemów, lecz starały się je zmarginalizować.

Podział ten nie przebiega w sposób czarno-biały. Andrzej Krzemieński, współautor propozycji, przyznaje, że jego model „nie jest akceptowany przez znaczącą część” komitetu i uważa za „zaskakujące”, że sprzeciw dwóch dostawców kompilatorów nie wystarczył do jego dyskwalifikacji.

3. C++26 odrzucone: co dalej ze standardem?

Decyzja nie należy do samego komitetu C++. Podejmie ją przewodniczący właściwego podkomitetu ISO (SC22) na podstawie rekomendacji komitetu, spodziewanej podczas spotkania w Búzios (Brazylia) w listopadzie. Zasady ISO przewidują cztery ścieżki: zrewidowany standard poddany nowemu 8-tygodniowemu głosowaniu; powrót do etapu Committee Draft (w celu ponownego głosowania po głębszych modyfikacjach); publikacja jako Technical Specification (C++26 nie byłoby oficjalnym standardem języka, lecz opcją implementacyjną); lub całkowite porzucenie projektu. W przypadku braku zatwierdzenia do końca 2027 roku projekt zostanie automatycznie anulowany.

Zwolennicy proponują ponowne głosowanie bez modyfikacji kontraktów, licząc na to, że oficjalne odpowiedzi komitetu przekonają kraje głosujące przeciw (odmowy National Bodies są bowiem również opatrzone komentarzami i pytaniami).

Jest to jednak ryzykowny zakład: nawet gdyby wszystkie 12 wstrzymujących się państw zagłosowało na „Tak”, 9 głosów przeciwnych nadal stanowiłoby ponad 25%. Trzeba by więc nie tylko przekonać wszystkich wstrzymujących się, ale także skłonić co najmniej 4 kraje do zmiany obozu.

Druga droga zakłada wycofanie kontraktów, aby opublikować resztę C++26, w tym niezwykle wyczekiwane funkcjonalności, takie jak statyczna refleksja (static reflection) oraz std::execution. Wycofanie to nie jest trywialne: wymaga przeredagowania wielu fragmentów normy i ponownego przejścia przez głosowanie jednostek krajowych. Konieczne będzie także odseparowanie mechanizmu bibliotecznego hardeningu od samych kontraktów. Jest on już szeroko wdrożony (zwłaszcza przez Google, które dzięki niemu wykryło ponad tysiąc błędów przy narzucie rzędu 0,3%), lecz mógłby ocaleć, ponieważ jego pierwotna wersja była specyfikowana bez kontraktów, a jej implementacje są od nich w praktyce odseparowane.

Istnieje precedens wycofania funkcji pod groźbą ostatecznego odrzucenia. W 2008 roku propozycja dodania konceptów (concepts) została wycofana z C++0x (późniejszego C++11). Powróciły one w znacznie lepszej formie w C++20. Tamto wycofanie miało jednak miejsce jeszcze przed pierwszym głosowaniem National Bodies.

Podsumowanie

Poza samymi kontraktami głosowanie to stawia fundamentalne pytanie o governance całego procesu. Dla jednych stanowi dowód na to, że zewnętrzna kontrola przewidziana przez ISO działa, gdy komitet ignoruje poważną opozycję. Dla innych tworzy niebezpieczny precedens: większość wewnątrz komitetu może zostać zablokowana przez mniejszość posiadającą silne wpływy w National Bodies. Spotkanie w Búzios pokaże, czy komitet wybierze kompromis — ratując C++26 bez kontraktów — czy pójdzie na zwarcie. W obu przypadkach płynie z tego nauka na przyszłość: uzasadnienie, dlaczego odrzuca się czyjeś zastrzeżenia, liczy się na równi z samym liczeniem głosów.

Co warto zapamiętać o odrzuceniu C++26

Jaka przyszłość czeka standard C++26?

Przypadek odrzucenia C++26 przez krajowe jednostki normalizacyjne stanowi historyczny punkt zwrotny w rozwoju języka. Wynik tego głosowania nie oznacza całkowitej rezygnacji ze standardu, lecz stanowi sprzeciw wobec forsowania kluczowej funkcjonalności — kontraktów (P2900) — kwestionowanej pod względem technicznym przez tak fundamentalne postaci jak Bjarne Stroustrup oraz twórcy kompilatorów.

Bezpośrednia uwaga przenosi się na spotkanie w Búzios oraz decyzję podkomitetu SC22: najbardziej pragmatycznym scenariuszem pozostaje wycofanie kontraktów, aby zabezpieczyć terminową publikację pozostałych, wyczekiwanych przełomów, w szczególności statycznej refleksji (static reflection) oraz std::execution.

Warto obserwować: Decyzje podkomitetu ISO SC22 oraz zrewidowany harmonogram do końca 2027 roku.
Dlaczego norma C++26 została odrzucona przez ISO?

Ostateczny draft normy C++26 został odrzucony przez krajowe jednostki normalizacyjne (13 głosów za, 9 przeciw, 12 wstrzymujących się, czyli poniżej wymaganego progu dwóch trzecich) z powodu kontrowersyjnej integracji kontraktów (propozycja P2900). Wpływowa mniejszość, na czele z twórcą języka Bjarne Stroustrupem oraz zespołami kompilatorów Microsoft i EDG, zarzuca projektowi brak gwarancji w czasie wykonywania kodu (runtime), niewystarczającą ziarnistość oraz zbyt niską dojrzałość techniczną.

Czy fakt, że C++26 zostało odrzucone, definitywnie anuluje standard?

Nie. Odrzucenie draftu C++26 w tym głosowaniu nie oznacza porzucenia projektu. Przewodniczący podkomitetu ISO (SC22) musi podjąć decyzję w ślad za spotkaniem w Búzios. Możliwe pozostają cztery scenariusze:

  • Szybka rewizja poddana nowemu 8-tygodniowemu głosowaniu;
  • Powrót do etapu Committee Draft w celu głębszej przebudowy;
  • Publikacja w formie specyfikacji technicznej (Technical Specification) bez statusu oficjalnego standardu;
  • Całkowite wycofanie kontraktów, aby opublikować resztę normy w pierwotnym terminie.
Co stanie się z innymi nowościami, takimi jak refleksja statyczna i std::execution?

Bardzo oczekiwane funkcje, takie jak statyczna refleksja (static reflection) czy biblioteka zrównoleglania std::execution, nie budzą merytorycznych zastrzeżeń. Jeśli komitet zdecyduje się na wycofanie kontraktów w celu odblokowania zatwierdzenia C++26, nowości te będą mogły zostać opublikowane w zrewidowanym standardzie, pod warunkiem terminowego wykonania prac nad redakcyjnym oddzieleniem specyfikacji.

Czym są kontrakty w C++ i na czym polega problem?

Kontrakty wprowadzają natywną składnię warunków wstępnych (pre), warunków końcowych (post) oraz asercji (contract_assert), mającą zastąpić tradycyjne makro assert. Krytyka dotyczy faktu, że ich aktywacja zależy w całości od opcji kompilacji bez możliwości zdefiniowania bezwzględnego, obowiązkowego kontraktu w kodzie, co rodzi ryzyko utraty kontroli w fazie linkowania (link) między bibliotekami skompilowanymi z różnymi ustawieniami.

Dokumenty referencyjne i źródła (propozycje ISO, głosy krytyczne i debaty)

Propozycja

  • P2900R14, Contracts for C++: przyjęta specyfikacja
  • P2899R1, Contracts for C++ — Rationale: uzasadnienie i pełna historia
  • P3471R4, Standard library hardening

Głosy krytyczne

  • P3573R0, Contract concerns (Stroustrup, Dos Reis, Vandevoorde, Spicer et al.)
  • P3829R0, Contracts do not belong in the language
  • P3835R0, Contracts make C++ less safe — full stop!: tryb mieszany
  • P3853R0, A thesis+antithesis=synthesis rumination on Contracts: ryzyko zabetonowania domyślnego zachowania
  • P4238R1, Returning C++26 for the Evaluation It Skipped: argument proceduralny
  • P4381R0, Chairing SG21 and then objecting to Contracts (Mea culpa Johna Spicera)

Głosy w obronie

  • P3846R1, C++26 Contract Assertions, Reasserted: odpowiedź punkt po punkcie na zastrzeżenia
  • P4433R0, Do not remove Contracts from C++26
  • P4388R0, Ship C++26
  • P3850R1, A proposed plan for extending Contracts in C++29
  • P3400R5, Controlling Contract-Assertion Properties: etykiety (labels)

Głos pośredni

  • P4020R0, Concerns about contract assertions (Krzemieński, współautor P2900)

Dokumenty oficjalne

  • N5028, komentarze jednostek krajowych na etapie CD (2025)
  • N5007, N5031, N5040: sprawozdania ze spotkań w Hagenbergu, Kona i Croydon