世界を動かす技術を、日本語で。

C++26が完了 - ISO C++規格会議の報告

概要

  • C++26 の技術的作業が完了し、ISOによる最終承認段階へ移行
  • 反射(Reflection)メモリ安全性向上契約(Contracts)std::execution が主な新機能
  • 業界での迅速な採用 が見込まれる理由と背景
  • C++29 に向けた更なるメモリ安全性強化の議論
  • 標準化作業の進行状況 と今後の展望

C++26の技術的作業完了と最終承認プロセス

  • ISO C++委員会 がロンドン・クロイドンにてC++26の技術作業を完了
  • 国際コメント 411件の対応を終え、最終文書(DIS)をISOへ提出準備
  • Phil Nash(Shaved Yaks)とStandard C++ Foundation がホスト、6日間の高品質な会議運営
  • 参加者は 24カ国・約210名 (現地130名・リモート80名)、新規ゲスト24名
  • 23のアクティブな分科会 が並行して議論、技術セッションも開催

C++26の注目機能:Fab Four Features

  • 反射(Reflection)
    • C++言語史上最大の進化、コンパイル時反射機能の導入
    • 言語自身の構造を記述・生成可能、抽象化表現力の飛躍的向上
  • メモリ安全性の向上
    • 未初期化ローカル変数の読み取りによる未定義動作(UB)を排除
    • 標準ライブラリの境界安全性強化(vector, span, string等でバグ防止)
    • GoogleやAppleで既に大規模導入、バグ修正・セグフォ率30%減少実績
  • 契約(Contracts)
    • 関数宣言に事前条件・事後条件・assert文を言語レベルで導入
    • 技術的懸念が残るも、委員会の大多数が導入を支持
  • std::execution(Sender/Receiver)
    • C++の非同期モデル、並列・並行処理の統一的フレームワーク
    • 安全な構造化並行性、データ競合抑止
    • ドキュメント・周辺ライブラリ不足のため、初期学習コストに注意

C++26の業界導入が早い理由

  • 高いユーザ需要
    • C++11以来の「全員が毎日使う」レベルの大型機能群
    • 反射・安全性強化など、幅広い現場で即時価値を発揮
  • 実装の進捗
    • GCC・ClangともにC++26機能の2/3以上を既に実装
    • reflection・contractsはGCCのtrunkに統合済み

C++29に向けた議論と安全性強化

  • 3年サイクルでC++29リリース予定
  • メモリ安全性の更なる強化 が大きな議題
    • 未定義動作の追加削減
    • SG23(安全性・セキュリティ分科会)でのプロファイル議論
    • Bjarne Stroustrupの型安全プロファイル案、Gabriel Dos Reis提案の一般プロファイル枠組み
    • AppleのOliver HuntによるWebKit大規模安全化事例報告
  • 「安全がデフォルト、ゼロオーバーヘッド原則は維持」
    • 必要に応じてopt-out可能、パフォーマンス重視の現場にも配慮

その他の進捗と機能安全関連

  • 契約チェックの適用拡大計画 の検討
  • 数量・単位ライブラリ(P3045R7) の進捗
    • SG6(数値分科会)、SG18(ライブラリ分科会)で議論
    • 安全性への寄与、現実の事故防止への可能性

今後の展望

  • C++26は新時代の幕開け
    • メモリ安全性・抽象化力・並列性の大幅向上
    • 実装・現場の両面からの速やかな普及が期待
  • C++29以降も「安全かつ効率的」な言語進化
    • 業界・学術界・OSSコミュニティの連携による更なる発展

Hackerたちの意見

一番の疑問は、この標準のモジュールシステムの小さな変更が、実際にもっと広く採用されることにつながるのかどうかだね。

いや、モジュールは失敗したアイデアだと思う。今の時点で主流になるとは全然思えないな。

C++のWGができる一番いいことは、モジュールとパッケージングに全リリースサイクルを使うことだと思う。新機能があるのはいいけど、C++を本当に殺してるのはCargoなんだよね。新しい世代の開発者が、cargo addで必要なものを簡単に追加できない言語を学ぼうと思うとは思えない。

いや、ほとんどの主要なコンパイラがヘッダーユニットをサポートしてないし、C++26の標準ライブラリヘッダーユニットなんてなおさらだよ。採用を促進するのは、CMakeがClangの二段階コンパイルモデルを採用することだと思う。それが実現すれば、冗長な前処理を避けられるから、すぐに全プロジェクトが移行するだろうね。今は並列処理の損失が採用を妨げてる。

正直、C++の開発をやめてほしいと思ってる。新しい不要な機能がどんどん追加されて、追いかけるのが大変なんだ。最近のC++コードを読んで、C++を知ってると思ってた自分が恥ずかしい。そんなレベルだよ。それに、C++のビルドシステムはひどい。ヘッダーファイルなんて必要ないはずだ。

これ、すごい!90年代にMSのC++チームで開発者やってたけど、RTTIが言語にとって真のリフレクションシステムに最も近いものだと思ってたんだよね。

ようやくリフレクションが来たね。最後にC++のコードに触ったのが5年前だけど、デストラクティングムーブを導入するのに委員会がどれくらいかかるのか気になるな。

うん、同じ気持ちだよ。5年前にRustに切り替える前にあったら助かった機能がたくさんあるね。

契約が受け入れられたことに少しがっかりしてる。すでに複雑さの限界を超えた言語にさらに複雑さを加える感じがするし、この機能には自分で足を引っ張る要素もあるから、正当化されるのか疑問だな。ビャーネの言葉を引用すると、>「約1年前に戻って、標準に入る前に投票できたら、何人かは反対票を投じた。今はもっと難しい問題がある。これは標準提案の一部だ。悪いと思う機能があるからといって、標準に反対票を投じるべきか?私はこれが悪いと思ってる。それはもっと難しい問題だ。人々は『ああ、これでたくさんの良いものが得られる』と思って賛成票を入れるけど、彼らは正しい。私たちは多くの複雑さと悪いものも得ている。この提案は、私の意見では膨れ上がった委員会のデザインで、しかも不完全だ。」

C++の契約設計については詳しくないけど、悪い選択がされた可能性はあるね。でも、契約はC++が次の進化のステップに必要なものだと思う。正しい設計のソフトウェアに使われるプログラミング言語(Ada、C++、Rust)は、テストではなく静的に任意のプロパティを示すために、証明アシスタントとの深い統合を可能にする必要がある。そのために契約が/その/重要な部分なんだよね。例えば、Ada Sparkを見てみて。

まあ、C++だしね。複雑さの予算はアメリカ政府の債務上限みたいなもんだよ。

C++のコントラクトは、すでにC++でやってることを標準化してるだけだよ。それに複雑さはどこにあるの?言語が標準的な相互運用可能な実装を提供してくれるから、自分で実装を書く必要がなくなるんだ。リフレクションのようなC++26の機能が複雑さを加えるという意見もあるけど、コントラクトに関してはその意見には賛成できないな。

引用元: https://youtu.be/tzXu5KZGMJk?t=3160

どのプロジェクトも「複雑さの予算」を定量化して、それに従ったことってあるのかな?機能が人間にとってどれだけの複雑さを持つかを決めるという考え方に興味があるんだ。それから、みんなが新しいものを受け入れる必要があると合意したときに、何を削除するかを決める政治的プロセスもね。

Bjarneがその機能が悪いと思ってるからって、それが本当に悪いわけじゃないよ。彼が間違ってることもあるしね。要するに、ほとんどの人は彼に同意してないから、たくさんの人がそれが良いと思ってるんだ。

「すでに複雑さの予算を超えた言語に対して」 ずっとそう思ってたけど、明らかに間違ってたみたい。もしかしたら、C++は過剰な複雑さの問題が当てはまらない唯一の言語なのかもね。

それ、天才的なアイデアだね。壊れたものをどんどん標準に追加して、修正するために互換性を壊さざるを得なくなるっていう。

90年代初頭にC++に契約機能を拡張として実装したんだけど、誰も欲しがらなかったんだよね。 https://www.digitalmars.com/ctg/contract.html

うわ、Bjarneが「> 膨れ上がった委員会のデザインで、しかも不完全だ」って思ってるなら、まさにその裏道で火がついてるって感じだね。

まず、準拠したコンパイラと標準ライブラリの実装が急速に進んでいるよ。C++26の開発中、どの時点でもGCCとClangはC++26の機能の3分の2をすでに実装してた。今、GCCはリフレクションとコントラクトがトランクにマージされて、リリースを待ってる状態。Clangのリフレクションとコントラクトはどれくらい進んでるの?

ClangのC++2c実装状況ページには、リフレクションと契約の両方に対して「いいえ」と書いてあるけど、GCCの方は「はい」ってなってるよ。https://clang.llvm.org/cxx_status.html https://gcc.gnu.org/projects/cxx-status.html

プログラマーがヘッダーファイルを扱わなきゃいけない限り、これらは豚に口紅を塗ってるだけだよ。

新しいプロジェクトでは使わないよ。CMake + ninjaはgcc、clang、MSVCでモジュールをサポートしてる。これは小規模から中規模のC++プロジェクトではデフォルトのスタックにすべきだね。Bazelも、非常に大きなコードベースのデフォルト選択肢だけど、C++20のモジュールをサポートしてるよ。

実際、事後条件と事前条件にはワクワクしてる。ほとんどの言語であまり使われてない機能だと思う。

初期化されていない変数の読み取りに関する「誤った動作」の再定義は本当に興味深いね:https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p27... 実行時コストがあるけど、再度未定義動作を強制する属性があって、そのコストを避けられるよ:int x [[indeterminate]]; std::cin >> x;

うーん、これもコンパイラフラグになるのかな?多分そうだろうね。だって、プロジェクトによっては手動で全ての変数を初期化したいっていうところもあるし。

Dは全ての変数を初期化するよ。初期化子を提供しなければ、コンパイラがデフォルトの初期化子を挿入するんだ。でも、本当に本当に初期化しないでおきたいなら、int x = void; って書けばいいよ。偶然に書かない場所でね。

std::executionはすごく興味深いけど、Sutterが警告しているように、始めるのは難しそうだね。このHPC Wireの記事では、標準C++を使ってCUDAとMPIの両方で非同期並列計算を活用する方法が紹介されてるよ。https://www.hpcwire.com/2022/12/05/new-c-sender-library-enab... 通信と計算を重ねるのは、高性能計算で「レイテンシを隠す」ための一般的な手法で、スケーリングを良くするんだ。今や標準C++を使って、特定のスケジューラに縛られずに並列アルゴリズムを表現できるようになったね。

私の意見を聞いてくれるなら(なんで聞いてくれないの? :-))、C++ WGにいくつかやってほしいことがあるんだ。1. restrictキーワードとその意味を標準化してほしい(構造体やクラスのフィールドには難しいけど、やるべきだと思う)。2. 統一された関数呼び出し構文!つまり、obj.f(arg)が単にf(obj, arg)を意味するようにしてほしい。これで、クラスのユーザーとしても作者としてもずっと楽になるよ。特にライブラリ作成の仕事ではね。それから、クラス名を静的メソッドの名前空間として使えるようにして、Obj::fという静的メソッドが単に名前空間Objのメソッドfになるようにしてほしい。3. コンパイラメーカーにABIの破壊をさせて、メモリを介さずにレジスタでラップされた値を渡せるようにしてほしい。詳しくはここを見てね: https://stackoverflow.com/q/58339165/1593077 4. 現在の標準ライブラリのアロケータをなくしてほしい。型特有で(馬鹿げてる)、ポインタを返すのではなくメモリの領域を返すようにしてほしい。それに、メモリの領域(アドレスとサイズはあるけど要素の型がない)も標準化すべきだね。