文書の一覧
全部で113本あります。
一部の記事は次の方に手伝っていただいています、ありがとうございました
もくじ
- N4984 WG21 June 2024 Admin Minutes of Meeting
- N4985 WG21 2024-06 St Louis Minutes of Meeting
- N4986 Working Draft, Programming Languages -- C++
- N4987 Editors' Report, Programming Languages -- C++
- P0260R10 C++ Concurrent Queues
- P0472R1 Put std::monostate in <utility>
- P0843R13 inplace_vector
- P0843R14 inplace_vector
- P0876R17 fiber_context - fibers without scheduler
- P0963R3 Structured binding declaration as a condition
- P1928R10 std::simd - Merge data-parallel types from the Parallelism TS 2
- P1928R11 std::simd - Merge data-parallel types from the Parallelism TS 2
- P2075R6 Philox as an extension of the C++ RNG engines
- P2300R10 std::execution
- P2319R0 Prevent path presentation problems
- P2389R2 dextents Index Type Parameter
- P2422R1 Remove nodiscard annotations from the standard library specification
- P2642R6 Padded mdspan layouts
- P2656R3 C++ Ecosystem International Standard
- P2664R7 Proposal to extend std::simd with permutation API
- P2686R4 constexpr structured bindings and references to constexpr variables
- P2761R2 Slides: Evaluating structured binding as a condition (P0963R2 presentation)
- P2761R3 Slides: Slides: Structured binding declaration as a condition (P0963R2 presentation)
- P2769R2 get_element customization point object
- P2848R1 std::is_uniqued
- P2863R6 Review Annex D for C++26
- P2863R7 Review Annex D for C++26
- P2865R5 Remove Deprecated Array Comparisons from C++26
- P2866R3 Remove Deprecated Volatile Features From C++26
- P2866R4 Remove Deprecated Volatile Features From C++26
- P2873R2 Remove Deprecated locale category facets for Unicode from C++26
- P2897R2 aligned_accessor: An mdspan accessor expressing pointer overalignment
- P2897R3 aligned_accessor: An mdspan accessor expressing pointer overalignment
- P2963R3 Ordering of constraints involving fold expressions
- P2989R2 A Simple Approach to Universal Template Parameters
- P2996R4 Reflection for C++26
- P3006R1 Launder less
- P3037R2 constexpr std::shared_ptr
- P3044R1 sub-string_view from string
- P3051R2 Structured Response Files
- P3064R2 How to Avoid OOTA Without Really Trying
- P3068R3 Allowing exception throwing in constant-evaluation
- P3085R3 noexcept policy for SD-9 (throws nothing)
- P3087R1 Make direct-initialization for enumeration types at least as permissive as direct-list-initializatio
- P3094R3 std::basic_fixed_string
- P3096R2 Function Parameter Reflection in Reflection for C++26
- P3124R0 2024-02 Library Evolution Poll Outcomes
- P3137R2 views::to_input
- P3138R2 views::cache_last
- P3144R1 Deprecate Delete of Incomplete Class Type
- P3144R2 Deleting a Pointer to an Incomplete Type Should be Ill-formed
- P3149R4 async_scope -- Creating scopes for non-sequential concurrency
- P3149R5 async_scope -- Creating scopes for non-sequential concurrency
- P3161R2 Unified integer overflow arithmetic
- P3164R1 Improving diagnostics for sender expressions
- P3164R2 Improving diagnostics for sender expressions
- P3168R2 Give std::optional Range Support
- P3175R3 Reconsidering the std::execution::on algorithm
- P3178R0 Retrieval of Exception Information
- P3178R1 Retrieval of Exception Information
- P3179R2 C++ parallel range algorithms
- P3182R1 Add container pop methods that return the popped value
- P3212R0 The contract of sort()
- P3223R1 Making std::istream::ignore less surprising
- P3235R1 std::print more types faster with less memory
- P3235R2 std::print more types faster with less memory
- P3235R3 std::print more types faster with less memory
- P3245R1 Allow [[nodiscard]] in type alias declarations
- P3248R1 Require [u]intptr_t
- P3255R1 Expose whether atomic notifying operations are lock-free
- P3265R2 Ship Contracts in a TS
- P3265R3 Ship Contracts in a TS
- P3288R1 std::elide
- P3288R2 std::elide
- P3288R3 std::elide
- P3290R1 Integrating Existing Assertions With Contracts
- P3294R1 Code Injection with Token Sequences
- P3296R1 let_with_async_scope
- P3297R1 C++26 Needs Contract Checking
- P3303R1 Fixing Lazy Sender Algorithm Customization
- P3309R1 constexpr atomic and atomic_ref
- P3310R1 Solving partial ordering issues introduced by P0522R0
- P3310R2 Solving partial ordering issues introduced by P0522R0
- P3314R0 2024-07 Library Evolution Polls
- P3319R1 Add an iota object for simd (and more)
- P3321R0 Contracts Interaction With Tooling
- P3323R0 cv-qualified types in atomic and atomic_ref
- P3325R0 A Utility for Creating Execution Environments
- P3325R1 A Utility for Creating Execution Environments
- P3325R2 A Utility for Creating Execution Environments
- P3326R0 favor ease of use
- P3328R0 Observable Checkpoints During Contract Evaluation
- P3330R0 User-defined Atomic Read-Modify-Write Operations
- P3331R0 Accessing The First and Last Elements in Associative Containers
- P3332R0 A simpler notation for PM
- P3335R0 Structured Core Options
- P3336R0 Usage Experience for Contracts with BDE
- P3338R0 Observe and ignore semantics in constant evaluation
- P3339R0 C++ Ecosystem IS Open License
- P3340R0 A Consistent Grammar for Sequences
- P3341R0 C++ Standard Library Ready Issues to be moved in St Louis, Jun. 2024
- P3342R0 Working Draft, Standard for C++ Ecosystem
- P3343R0 Contracts - What are we doing here (EWG Presentation)
- P3344R0 Virtual Functions on Contracts (EWG - Presentation for P3097)
- P3345R0 Core Language Working Group "ready" Issues for the June, 2024 meeting
- P3351R0 views::scan
- P3354R0 Slides for P3233R0
- P3355R0 Fix submdspan for C++26
- P3356R0 non_invalidating_vector
- P3357R0 NRVO with factory and after_factory
- P3358R0 SARIF for Structured Diagnostics
- P3359R0 Slides for P3298R0 - Implicit conversion functions
- P3360R0 Slides for P3312R0 - Overload Set Types
- おわり
N4984 WG21 June 2024 Admin Minutes of Meeting
2024年3月4日に行われた、WG21管理者ミーティングの議事録。
前回(東京会議の前)からどのような活動があったかや、St Louis会議で何をするかなどの報告がなされています。
N4985 WG21 2024-06 St Louis Minutes of Meeting
2024年6月にSt Louisで行われたWG21全体会議の議事録
N4986 Working Draft, Programming Languages -- C++
N4987 Editors' Report, Programming Languages -- C++
↑の変更点をまとめた文書。
P0260R10 C++ Concurrent Queues
標準ライブラリに並行キューを追加するための設計を練る提案。
以前の記事を参照
- P0260R5 C++ Concurrent Queues - [C++]WG21月次提案文書を眺める(2023年01月)
- P0260R7 C++ Concurrent Queues - [C++]WG21月次提案文書を眺める(2023年07月)
- P0260R8 C++ Concurrent Queues - [C++]WG21月次提案文書を眺める(2024年04月)
- P0260R9 C++ Concurrent Queues - [C++]WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- St. Louis会議におけるSG1からのフィードバックを実装
- コンセプトを3つに分割
try_*はロックフリーであることを要求(エラーコードbusyと共にis_always_lock_freeを削除capacity()を削除- discussion points forSG1、TS ship vehicleを削除
- 設計部分の一般的なクリーンアップ
などです。
P0472R1 Put std::monostate in <utility>
std::monostateを<utility>からも利用できるようにする提案。
std::monostateはstd::variantにおいて空の状態を表現するための型です。その値はデフォルト構築状態しか取ることができず、メンバ関数はありません。しかし、std::variantの諸特性(コピー/ムーブ/比較など)を妨げないようにするために一通りのそれらの操作が可能になっており、regularコンセプトを満たす型になっています。
そのため、std::monostateはstd::variantに限らず、情報が無い・状態を持たない・ある種の無効状態などの状態を表現する型として使用でき、特にテンプレートパラメータで型を指定する場合にそのような特別な状態を表現するのにvoid型の代わりに使用することができます。そのような場所では、voidの特殊性(値を取れない、regularでないなど)によって実装が面倒になる場合が多かったのですが、std::monostateはその代わりに使用可能な丁度便利な型になっています。
template<typename ExtraInformation = std::monostate> class Data { ... // voidだとエラーになる ExtraInformation m_extraInformation; };
このような用途により汎用的に使用できるように、std::monostateを<utility>からでも利用できるようにしようとする提案です。
提案より、ユースケースの例
- コンテナ型のテスト
- カスタム(オリジナル)の
vectorやsetが要素型に対して不要な仮定を行っていないかどうかをチェックするのに使用可能 std::monostateはその要素型として使用可能な最もシンプルな型であり、std::monostateで動作することを確かめれば要素型に対する不用意な要求を行っていないことを確認できる
- カスタム(オリジナル)の
- 特別な状態・場合を表すテンプレートパラメータとして
- 例えば、
std::futureはそれが同期するタイミング以外の情報が無いことを表すためにstd::future<void>特殊化が利用できる - ただ、
voidの性質の悪さによりそれを検出して特別扱いするTMPコードが必要になる
- 例えば、
- 例外をラップして返すcallableラッパ
- 渡されたcallableを呼び出し、その際に送出される例外をキャッチして戻り値に重畳して返す呼び出しラッパ実装を考える
- この場合、その戻り値は
std::optional/std::expcetedになるが、ラップ対象のcallableの戻り値型がvoidだった場合のサポートが厄介 std::monostateを使用すると、戻り値によらずコードを共通化できるようになる
ただし、後方互換のために<variant>から削除することは提案していません。あくまで両方のヘッダで利用できるようにしようとするものです。
P0843R13 inplace_vector
↓
P0843R14 inplace_vector
静的な最大キャパシティを持ちヒープ領域を使用しないstd::vectorであるinplace_vectorの提案。
以前の記事を参照
- P0843R5 static_vector - [C++]WG21月次提案文書を眺める(2022年08月)
- P0843R6 static_vector - [C++]WG21月次提案文書を眺める(2023年05月)
- P0843R8
inplace_vector- [C++]WG21月次提案文書を眺める(2023年07月) - P0843R9
inplace_vector- [C++]WG21月次提案文書を眺める(2023年09月) - P0843R10
inplace_vector- [C++]WG21月次提案文書を眺める(2024年02月) - P0843R11
inplace_vector- [C++]WG21月次提案文書を眺める(2024年04月) - P0843R12
inplace_vector- [C++]WG21月次提案文書を眺める(2024年05月)
R13での変更は、条件付きconstexprの条件をis_trivial_t<T>がtrueの場合に変更したことです。R14での変更はよくわかりません。
この提案は、2024年6月の全体会議でC++26に向けて採択されています。
P0876R17 fiber_context - fibers without scheduler
スタックフルコルーチンのためのコンテキストスイッチを担うクラス、fiber_contextの提案。
以前の記事を参照
- P0876R11
fiber_context- fibers without scheduler - WG21月次提案文書を眺める(2022年10月) - P0876R12
fiber_context- fibers without scheduler - WG21月次提案文書を眺める(2023年02月) - P0876R13
fiber_context- fibers without scheduler - WG21月次提案文書を眺める(2023年04月) - P0876R14
fiber_context- fibers without scheduler - WG21月次提案文書を眺める(2023年10月) - P0876R15
fiber_context- fibers without scheduler - WG21月次提案文書を眺める(2024年02月) - P0876R16
fiber_context- fibers without scheduler - WG21月次提案文書を眺める(2024年04月)
このリビジョンでの変更も多いですが、概ね文言レベルの調整です。
P0963R3 Structured binding declaration as a condition
構造化束縛宣言を条件式を書くところで書けるようにする提案。
以前の記事を参照
- P0963R1 Structured binding declaration as a condition - WG21月次提案文書を眺める(2023年08月)
- P0963R2 Structured binding declaration as a condition - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は、提案する文言の修正と、この機能を有効化する場合のコーナーケースをcondition構文要素の外側でケアしたことなどです。
この提案は、2024年6月の全体会議でC++26に向けて採択されています。
P1928R10 std::simd - Merge data-parallel types from the Parallelism TS 2
↓
P1928R11 std::simd - Merge data-parallel types from the Parallelism TS 2
std::simd<T>をParallelism TS v2から標準ライブラリへ移す提案。
以前の記事を参照
- P1928R1 Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2022年10月)
- P1928R2 Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2023年01月)
- P1928R3 Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2023年02月)
- P1928R4
std::simd- Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2023年05月) - P1928R6
std::simd- Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2023年07月) - P1928R7
std::simd- Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2023年10月) - P1928R8
std::simd- Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2023年12月) - P1928R9
std::simd- Merge data-parallel types from the Parallelism TS 2 - WG21月次提案文書を眺める(2024年05月)
R10での変更は
- “the indicated operator”ではなく“op”を使用
- 右辺オペランドに
simd-size-typeがあるシフト演算子の制約を修正 - P3275で削除されたnon-const
operator[]に関する記述を削除 - intrinsics conversionを推奨プラクティスにする
simd_flagsテンプレートパラメータを説明専用にするsimd_alignmentを実装定義にしない- “supported”を“enabled or disabled”に言い換え
- [simd.overview]から[simd.mask.overview]へ改善された文言を適用
- ブロードキャストコンストラクタに関するLWGコメントを追記
- ブロードキャスト制約を使用しないようにジェネレータコンストラクタを規定しなおす
- 隣接イテレータでは
to_addressを使用するようにする- 要素ごとに範囲をイテレーションするのではなく、範囲全体を
memcpyすることを許可する意図を明確にしている
- 要素ごとに範囲をイテレーションするのではなく、範囲全体を
このリビジョンでの変更は
- C++26をターゲットとして、SG1とLEWG向けに対応
- (改善および調整された)TS仕様をISにマージするように求める
- TSの経験の結果としてABIタグを削除したことについての議論を追加し、現状を変更するために投票を求める
- テンプレートパラメータ
Tをsimd_abi::fixed_sizeに追加 simd_abi::compatibleを削除simd_abi::abi_stableを追加(ただし削除を要求する- GCCリリースでのTS実装について言及
- 関連提案への参照を追加
- [numbers]の節番号を最新のドラフトに調整
- 未解決の質問を追加
- [simd]の正しい節はどこ?
- rangesとの統合
simd_maskジェネレータコンストラクタを追加- 見出しに一貫して
simdとsimd_maskを追加 experimentalとparallelism_v2名前空間を削除- N4808 (Parallelism TS 2)に対するdiff有無で文言を二回提示する
- デフォルトのロード/ストアフラグを
element_alignedに設定 - 条件付き
explicitコンストラクタによるキャストの一般化 - 名前付きキャスト関数を削除
などです。
この提案は次のリビジョンが2024年11月の全体会議で承認され、C++26に採択されています。
P2075R6 Philox as an extension of the C++ RNG engines
<random>にPhiloxというアルゴリズムベースの新しい疑似乱数生成エンジンを追加する提案。
以前の記事を参照
- P2075R1 : Philox as an extension of the C++ RNG engines - WG21月次提案文書を眺める(2020年07月)
- P2075R2 Philox as an extension of the C++ RNG engines - WG21月次提案文書を眺める(2023年01月)
- P2075R3 Philox as an extension of the C++ RNG engines - WG21月次提案文書を眺める(2023年10月)
- P2075R4 Philox as an extension of the C++ RNG engines - WG21月次提案文書を眺める(2024年02月)
- P2075R5 Philox as an extension of the C++ RNG engines - WG21月次提案文書を眺める(2024年04月)
このリビジョンでの変更は、LWGのフィードバックを受けて提案する文言を修正したことです。
この提案は、2024年7月に行われた全体会議でC++26に向けて採択されています。
P2300R10 std::execution
P0443R14のExecutor提案を置き換える、任意の実行コンテキストで任意の非同期処理を構成・実行するためのフレームワークおよび非同期処理モデルの提案。
以前の記事を参照
- P2300R0
std::execution- WG21月次提案文書を眺める(2021年06月) - P2300R1
std::execution- WG21月次提案文書を眺める(2021年07月) - P2300R2
std::execution- WG21月次提案文書を眺める(2021年11月) - P2300R3
std::execution- WG21月次提案文書を眺める(2021年12月) - P2300R4
std::execution- WG21月次提案文書を眺める(2022年01月) - P2300R5
std::execution- WG21月次提案文書を眺める(2022年04月) - P2300R6
std::execution- WG21月次提案文書を眺める(2023年02月) - P2300R7
std::execution- WG21月次提案文書を眺める(2023年05月) - P2300R9
std::execution- WG21月次提案文書を眺める(2024年04月)
R10での変更は
- 修正
connectとget_completion_signaturesをtransform_senderを使用するように修正- P3303R0を適用
ensure_started、start_detached、execute、execute_may_block_callerを削除- P3187R1を適用
splitの仕様で、receiverが2回完了する可能性があったのを修正stopped_as_optionalを子のsenderが2つ以上の値で完了する場合に対応できるように修正queryable、stoppable_source、stoppable_callback_forのコンセプトを説明専用にした
- 機能の強化
operation_stateコンセプトでは、操作状態モデルがqueryableである必要がなくなったget_delegatee_schedulerクエリをget_delegation_schedulerに変更- 環境の
readをread_envに変更 read_envのsenderのインスタンスを返すクエリのnullary形式を削除get_scheduler()はread_env(get_scheduler)の別記ではなくなった(他のクエリも同様)
- 機能テストマクロ
__cpp_lib_sendersを追加 transferがcontinues_onに、onがstarts_onに変更され、starts_onとcontinues_onを組み合わせた新しいonアルゴリズムを追加- P3175R3を適用
- ライブラリの概要に
simple-allocatorコンセプトが追加され、get_allocator()クエリの仕様がされに基づいて指定するようになった - 新しい
onアルゴリズムで使用するために、説明専用のsenderアダプタwrite-envを追加
などです。
この提案は2024年6月の全体会議で承認され、C++26 WDに導入されています。
P2319R0 Prevent path presentation problems
filesystem::pathの.string()メンバ関数を非推奨にして、代わりのメンバ関数を追加する提案。
filesystem::pathの.string()メンバ関数はパス文字列をネイティブエンコーディングに変換したstd::stringを返します。ネイティブエンコーディングとは「OS依存のパス名の現在のエンコーディング」です。
これによって、Windowsでは次のようなコードにおいて
std::filesystem::path p(L"Выявы"); std::print("{}\n", p); std::print("{}\n", p.string());
全てのコードページとローカライズ設定がベラルーシ語に設定されていて、ソースコードエンコーディングとリテラルエンコーディングの両方がUTF-8である場合でも、.string()メンバ関数の結果は文字化けを起こします。
Выявы �����
ネイティブエンコーディングとはリテラルエンコーディングでもロケールエンコーディングでもなく、この変換は通常何らかの損失を伴います。例えば、同じ条件のシステムで、次のようなコードはstd::runtime_error例外を送出します
std::filesystem::path p(L"Obrázky"); std::string s = p.string();
Windowsにおけるネイティブエンコーディングとは、コンソールに設定されたコードページとは別のアクティブコードページと呼ばれるエンコーディングであり、これは通常ASCII互換の非UTF-8エンコーディングになっています。一方で、Windowsにおけるpathオブジェクトはユニコード(wchar_t文字列)で文字を保持しているため、.string()の呼び出しではユニコード文字列からの変換が入り、必ずしもすべての文字が変換できるわけではありません。
上記例外を投げる例は突き詰めるとWideCharToMultiByte()関数でエラーが起きていると思われますが、なぜエラーが起きるのかは不明です(おそらくERROR_NO_UNICODE_TRANSLATIONエラーだと思われる)。
アクティブコードページは実行時のコマンドやAPI呼び出しで変更されるほかPCのローカライズ設定によっても変化するため、.string()は実行時のそれらの設定を受けて結果が変わり、テスト環境ではエラーが起きず本番環境ではエラーが起こるということが容易に起こります。
まとめると、filesystem::path::string()には次のような問題があります
- iostream、
std::format、std::printなどのほぼすべての標準テキスト処理およびI/O機能と互換性のないエンコーディングを使用する - エラーが非常に発生しやすく、プログラムが異なる環境にデプロイされた後や実行時構成変更後に発生する可能性のある文字列変換の問題が見過ごされやすい
- POSIX環境では上記のような問題はないものの、追加のメモリ確保と文字列コピーを行う非効率な
native()でしかないため、移植性のあるプログラムにおいて使用が難しい
これらの事は、非英語圏のC++ユーザーに不釣り合いな悪影響を及ぼし、C++言語を国際化対応されローカライズされたプログラムを記述するための言語としての魅力を削いでいます。
この提案では、filesystem::path::string()を非推奨にするとともに、その役割を分割して担う2つの関数を追加することを提案しています。追加する関数は次の2つです
system_string()display_string()
また、同様の問題がある.generic_string()(POSIXのパス形式にしたうえでパス文字列を返す)関数もgeneric_system_string()とgeneric_display_string()の2つに分割します。
これにより、先程の例は基本的にdisplay_string()を使うことで改善されます
std::filesystem::path p(L"Выявы"); std::print("{}\n", p); std::print("{}\n", p.display_string());
Выявы Выявы
std::filesystem::path p(L"Obrázky"); std::string s = p.display_string(); // 例外を投げない
P2389R2 dextents Index Type Parameter
std::dextentsから、整数型の指定を省略する提案。
以前の記事を参照
- P2389R0
dextentsIndex Type Parameter - WG21月次提案文書を眺める(2024年02月) - P2389R1
dextentsIndex Type Parameter - WG21月次提案文書を眺める(2024年04月)
このリビジョンでの変更は、提案する文言のコード中の斜体の表記を修正したことです。
この提案は2024年7月の全体会議でC++26に向けて採択されています。
P2422R1 Remove nodiscard annotations from the standard library specification
規格書における標準ライブラリの関数から、[[nodiscard]]を取り除く提案。
このリビジョンでの変更はよくわかりません。
この提案は2024年7月の全体会議でC++26に向けて採択されています。
P2642R6 Padded mdspan layouts
std::mdspanでpadding strideをサポートするためのレイアウト指定クラスを追加する提案。
以前の記事を参照
- P2642R0 Padded mdspan layouts - WG21月次提案文書を眺める(2022年09月)
- P2642R1 Padded mdspan layouts - WG21月次提案文書を眺める(2022年10月)
- P2642R2 Padded mdspan layouts - WG21月次提案文書を眺める(2023年01月)
- P2642R3 Padded mdspan layouts - WG21月次提案文書を眺める(2023年07月)
- P2642R4 Padded mdspan layouts - WG21月次提案文書を眺める(2023年10月)
- P2642R5 Padded mdspan layouts - WG21月次提案文書を眺める(2023年12月)
このリビジョンでの変更は
- 提案している2つのレイアウトマッピングクラスのデフォルトコンストラクタのインライン定義を削除
- 既にその後のテキストで指定されていたため
- [mdspan.layout.general]の更新を修正
- 保存された追加ストライドを初期化するためのコンストラクタの文言と事前条件を修正
- LWGレビューからのフィードバックに対応
などです。
この提案は2024年3月の全体会議でC++26に向けて採択されています。
P2656R3 C++ Ecosystem International Standard
C++実装(コンパイラ)と周辺ツールの相互のやり取りのための国際規格を発効する提案。
以前の記事を参照
- P2656R0 C++ Ecosystem International Standard - WG21月次提案文書を眺める(2022年10月)
- P2656R1 C++ Ecosystem International Standard - WG21月次提案文書を眺める(2023年01月)
- P2656R2 C++ Ecosystem International Standard - WG21月次提案文書を眺める(2023年02月)
このリビジョンでの変更は
- parallel processを削除(現時点では関連性が無いため
- レビュープロセスの明確な手順を指定
- EWGの設計承認とCWGの文言承認の定期的なレビューに準ずる
- 目標の条件と順序を微調整して、ドラフトの概要を反映する
- 現在および近い将来の見通しを反映させるため、タイムラインを更新
などです。
P2664R7 Proposal to extend std::simd with permutation API
std::simdに、permute操作のサポートを追加する提案。
以前の記事を参照
- P2664R0 Proposal to extend
std::simdwith permutation API - WG21月次提案文書を眺める(2022年11月) - P2664R1 Proposal to extend
std::simdwith permutation API - WG21月次提案文書を眺める(2023年02月) - P2664R3 Proposal to extend
std::simdwith permutation API - WG21月次提案文書を眺める(2023年05月) - P2664R4 Proposal to extend
std::simdwith permutation API - WG21月次提案文書を眺める(2023年10月) - P2664R5 Proposal to extend
std::simdwith permutation API - WG21月次提案文書を眺める(2023年12月) - P2664R6 Proposal to extend
std::simdwith permutation API - WG21月次提案文書を眺める(2024年01月)
このリビジョンでの変更は、P3299R0と一致するように、配列外参照するgather/scatter操作のデフォルトの動作をUBにしたことです。
P2686R4 constexpr structured bindings and references to constexpr variables
構造化束縛にconstexpr指定できるようにする提案。
以前の記事を参照
- P2686R0 Updated wording and implementation experience for P1481 (constexpr structured bindings) - WG21月次提案文書を眺める(2022年10月)
- P2686R1 Updated wording and implementation experience for P1481 (constexpr structured bindings) - WG21月次提案文書を眺める(2022年10月)
- P2686R2 Updated wording and implementation experience for P1481 (constexpr structured bindings) - WG21月次提案文書を眺める(2023年09月)
- P2686R3 constexpr structured bindings and references to constexpr variables - WG21月次提案文書を眺める(2024年02月)
このリビジョンでの変更は
- ”constituent values”と”constituent references”の定義がわずかに変更された(意味は変わらない
- 不正確だった”at a point [...] namespace scope”という表現は、名前空間スコープの最も近い次のポイントを参照するように変更された
- どの変数がconstexpr-referenceableなのかを示す文言の例は、どの変数がconstexpr-referenceableではないのかを明確にするために更新
- constexpr-referenceableの定義を明確にするために新しい用語を導入
- ”constant initialized”と
constexpr変数宣言の要件の間の重複した指定を減らすために、新しい用語を導入 requires式によって導入された関数パラメータスコープは無視されるようになった- 定数評価中の構造化束縛のセマンティクスを表す追加の例を追加
- ユースケースが無かったため、機能テストマクロを削除
- 代わりに、
__cpp_constexprと__cpp_structured_bindingsの両方をバンプ
- 代わりに、
などです。
この提案はCWGのレビューを完了していますが、実装経験が上がってくるのを待機しているようです。
P2761R2 Slides: Evaluating structured binding as a condition (P0963R2 presentation)
↓
P2761R3 Slides: Slides: Structured binding declaration as a condition (P0963R2 presentation)
P0963R1の紹介スライド。
このリビジョンでの変更は明示的ではありませんが、スライドの説明を調整しているようです(なぜかピコ太郎氏が登場しています)。
P2769R2 get_element customization point object
tuple-likeなオブジェクトから特定のインデックスの要素を抜き出すCPOの提案。
以前の記事を参照
- P2769R0
get_elementcustomization point object - WG21月次提案文書を眺める(2023年01月) - P2769R1
get_elementcustomization point object - WG21月次提案文書を眺める(2023年05月)
このリビジョンでの変更は
- 標準でユーザー定義のタプル型をサポートする追加のモチベーションを追加
tuple-likeコンセプトに変更を提案
などです。
ここで提案されているget_elementCPOがユーザー定義のタプル型をサポートすべきモチベーションとは、現在の標準にそれを受け止める物が無いことです。
現在の標準ライブラリには5つのタプル互換な型が存在しており、タプルをサポートするライブラリはそれらの型をサポートしています。これらの型はタプルプロトコルを実装することでタプル互換を達成しているためユーザー定義型でも同様に達成できそうですが、std::getがカスタマイズポイントではないことによってそれは妨げられています。
一方、言語ではユーザー定義タプル型がきちんとサポートされている場所があります。例えば構造化束縛ではget()関数を適切に見つけるために特別なルールを追加しています。ただしこのような扱いは場所によって異なっており、elements_viewでは標準ライブラリの型以外をサポートしていなかったりします。
ここで提案しているget_elementCPOをstd::getに変わるタプルの要素取得のためのカスタマイゼーションポイントとしておくことで、これを使用してタプルプロトコルをユーザー定義型に対して完全にオープンにすることができるようになります。
P2848R1 std::is_uniqued
範囲内に重複する隣接要素がないかを調べる std::is_uniqued, std::ranges::is_uniqued を <algorithm> に追加する提案。
以前の記事を参照
このリビジョンでの変更は
- 機能テストマクロの追加
- 命名に関する議論の追加
などです。
P2863R6 Review Annex D for C++26
↓
P2863R7 Review Annex D for C++26
現在非推奨とマークされている機能について、C++26で削除/復帰を検討する提案。
以前の記事を参照
- P2863R0 Review Annex D for C++26 - WG21月次提案文書を眺める(2023年05月)
- P2863R1 Review Annex D for C++26 - WG21月次提案文書を眺める(2023年08月)
- P2863R2 Review Annex D for C++26 - WG21月次提案文書を眺める(2023年10月)
- P2863R3 Review Annex D for C++26 - WG21月次提案文書を眺める(2023年12月)
- P2863R4 Review Annex D for C++26 - WG21月次提案文書を眺める(2024年02月)
- P2863R5 Review Annex D for C++26 - WG21月次提案文書を眺める(2024年04月)
R6およびこのリビジョンでの変更は主に追跡中の提案のステータス更新です。R7では追加でレビュー済みの提案に関する会議メモを記録しています。
P2865R5 Remove Deprecated Array Comparisons from C++26
C++20の一貫比較仕様に伴って非推奨とされた、配列間の比較を削除する提案。
以前の記事を参照
- P2865R0 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年05月)
- P2865R1 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年07月)
- P2865R2 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年08月)
- P2865R3 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年09月)
- P2865R4 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年12月)
このリビジョンでの変更は、最新のWDに追随したことのみです。
P2866R3 Remove Deprecated Volatile Features From C++26
↓
P2866R4 Remove Deprecated Volatile Features From C++26
C++20で非推奨とされたvolatile関連の機能を削除する提案。
以前の記事を参照
- P2865R0 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年05月)
- P2865R1 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2023年09月)
- P2865R2 Remove Deprecated Array Comparisons from C++26 - WG21月次提案文書を眺める(2024年04月)
R3での変更は
- すべてのワーキンググループにおけるC++26のレビューの概要を記録
std::atomicクラステンプレートの現在非推奨ではないものに対する変更を延期- 最新のWDに追随
- Annex Cに欠けていた根拠を追加
このリビジョンでの変更は
- St Louis会議でのCWGレビューを記録
- 微妙な変更を説明するためにコアの文言計画を更新
- Cとの互換性に関する懸念を収集するために、SG22に送付
volatile修飾された関数引数の削除に関するEWGの懸念を提起- コア言語とライブラリの文言更新
などです。
P2873R2 Remove Deprecated locale category facets for Unicode from C++26
C++20で非推奨とされたロケールカテゴリファセットをC++26で削除する提案。
以前の記事を参照
- P2873R0 Remove Deprecated locale category facets for Unicode from C++26 - WG21月次提案文書を眺める(2023年05月)
- P2873R1 Remove Deprecated locale category facets for Unicode from C++26 - WG21月次提案文書を眺める(2024年04月)
このリビジョンでの変更は
- iostreamsに精通していない人向けにロケールカテゴリファセットに関する背景情報を追加
- “locale dependent” という用語を “locale-specific” に置き換え
Wdeprecatedを使用してもGCCが非推奨警告を出力しないことを確認- 文言の更新
などです。
P2897R2 aligned_accessor: An mdspan accessor expressing pointer overalignment
↓
P2897R3 aligned_accessor: An mdspan accessor expressing pointer overalignment
mdspanのアクセサポリシークラスに、参照する領域ポインタにstd::assume_alignedを適用してアクセスするaligned_accessorの提案。
以前の記事を参照
- P2897R0
aligned_accessor: An mdspan accessor expressing pointer overalignment - WG21月次提案文書を眺める(2023年05月) - P2897R1
aligned_accessor: An mdspan accessor expressing pointer overalignment - WG21月次提案文書を眺める(2023年10月)
R2での変更は
is_sufficiently_alignedからconstexprを削除- R1のLEWGレビューでのオプションの提案についての議論の追加
- P2389R2が先にWDに入ったため、例における
dextentsの使用をdimsに置き換え aligned_accessorに小さなアライメントから大きなアライメントへの明示的変換コンストラクタが無い理由を説明するセクションを追加- 完全な実装とデモを含むCompiler Explorerリンクを追加
このリビジョンでの変更は、David Sankel氏からのレビューを適用したことです。
P2963R3 Ordering of constraints involving fold expressions
コンセプトの制約式として畳み込み式を使用した場合に、意図通りの順序付を行うようにする提案。
以前の記事を参照
- P2963R0 Ordering of constraints involving fold expressions - WG21月次提案文書を眺める(2023年09月)
- P2963R1 Ordering of constraints involving fold expressions - WG21月次提案文書を眺める(2024年01月)
- P2963R2 Ordering of constraints involving fold expressions - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- CWGのレビューを受けての文言の改善
- 両方の制約が等価なテンプレートパラメータを持つことを要求することで、空のパックがある場合の矛盾から保護する
- これは、サイズが同じであることを保証する
- foldから展開された制約の分解により、atomic制約が非
bool型となる可能性があるためAnnex Cのエントリを追加
などです。
この提案は2024年6月の全体会議で採択され、C++26WDにマージされています。
P2989R2 A Simple Approach to Universal Template Parameters
より限定されたユニバーサルテンプレートパラメータの提案。
以前の記事を参照
- P2989R0 A Simple Approach to Universal Template Parameters - WG21月次提案文書を眺める(2023年10月)
- P2989R1 A Simple Approach to Universal Template Parameters - WG21月次提案文書を眺める(2024年02月)
このリビジョンでの変更は、ABIとinjected-class-namesに関するセクションを追加したことです。
P2996R4 Reflection for C++26
値ベースの静的リフレクションの提案。
以前の記事を参照
- P2996R0 Reflection for C++26 - WG21月次提案文書を眺める(2023年10月)
- P2996R1 Reflection for C++26 - WG21月次提案文書を眺める(2023年12月)
- P2996R2 Reflection for C++26 - WG21月次提案文書を眺める(2024年02月)
- P2996R3 Reflection for C++26 - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- Unicodeとの親和性を高めるために
name_of()関数ファミリを変更し、u8name_of(), u8qualified_name_of(), u8display_name_of()を追加 reflect_resultをreflect_value(), reflect_object(), reflect_function()の3つの関数に分離- エイリアスのリフレクション(鏡像)の比較およびリンケージのルールを厳格化
is_noexcept()をより広いタイプのエンティティに適用可能なように変更- アクセス可能なクラスメンバをリフレクションするためのAPIを再構築
test_type, test_typesをtest_traitに変更has_module_linkage()を追加- 変数とそのオブジェクトのリフレクションの違いを明確化
object_of()を追加- 文言の追加
などです。
P3006R1 Launder less
バイト配列上に構築した別の型のオブジェクトへのポインタをより直感的に取得できる様にする提案。
このリビジョンでの変更は
- 「Impact on the optimizers」の説を追加
std::launderの使用は最適化を阻害するのみ、とのこと
- 提案する文言を追加
などです。
この提案はEWGのレビューを通過してCWGのレビュー中です。
P3037R2 constexpr std::shared_ptr
std::shared_ptrを定数式でも使える様にする提案。
以前の記事を参照
- P3037R0
constexpr std::shared_ptr- WG21月次提案文書を眺める(2023年12月) - P3037R1
constexpr std::shared_ptr- WG21月次提案文書を眺める(2024年04月)
このリビジョンでの変更は
- 提案する文言の追加
- いくつかの関数から
constexprを取り除いた
などです。
除外されたのは、例外やreinterpret_castなどの定数式では実行できない操作を含むものです。
P3044R1 sub-string_view from string
std::stringから直接string_viewを取得する関数を追加する提案。
以前の記事を参照
このリビジョンでの変更は、関数名と関数に対する参照修飾に関する議論を追加したことです。
P3051R2 Structured Response Files
ツールが他のツールにコマンドラインオプションをファイルで引き渡す方法についての提案。
以前の記事を参照
- P3051R0 Structured Response Files - WG21月次提案文書を眺める(2023年12月)
- P3051R1 Structured Response Files - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- 1度に1つの引数/オプションフィールドのみ許可
- 引数とオプションの処理の概念を定義
- オプションの混乱を避けるため、文言セクション名を"Structured Options"から"Structured Parameters"に変更
- オプションをJSONオブジェクトに変更し、独自の構造化オプションモデルへ移行
- 設計上の選択の根拠を追跡するため、"design considerations"セクションを追加
- flagオプションは
bool値としてより自然に表現できるため削除
などです。
P3064R2 How to Avoid OOTA Without Really Trying
C++コンパイラによる実装においては、OOTA問題が発生しないことを解説する文書。
以前の記事を参照
- P3064R0 How to Avoid OOTA Without Really Trying - WG21月次提案文書を眺める(2024年04月)
- P3064R1 How to Avoid OOTA Without Really Trying - WG21月次提案文書を眺める(2024年05月)
R1での変更は、アトミックロードのinventing, duplicating, もしくは repurposingが算術の基本法則に違反する可能性がある事を示す、非OOTAの例を追加
このリビジョンでの変更は、St. Louis会議でのフィードバックを取り入れ、OOTAを回避するために何も変更をする必要がないという主張を明確化したことです。
P3068R3 Allowing exception throwing in constant-evaluation
定数式においてthrow式による例外送出およびtry-catchによる例外処理を許可する提案。
以前の記事を参照
- P3068R0 Allowing exception throwing in constant-evaluation. - WG21月次提案文書を眺める(2024年02月)
- P3068R1 Allowing exception throwing in constant-evaluation - WG21月次提案文書を眺める(2024年04月)
- P3068R2 Allowing exception throwing in constant-evaluation - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
bad_alloc、bad_array_new_length、bad_typeidをconstexpr化- 文言からrecommended practiceを削除
dynamic_castとtypeid空の例外送出を許可するために文言を調整- 機能テストマクロの追加
などです。
P3085R3 noexcept policy for SD-9 (throws nothing)
ライブラリ関数にnoexceptを付加する条件についてのポリシーの提案。
以前の記事を参照
- P3085R0
noexceptpolicy for SD-9 (throws nothing) - WG21月次提案文書を眺める(2024年02月) - P3085R1
noexceptpolicy for SD-9 (throws nothing) - WG21月次提案文書を眺める(2024年04月) - P3085R2
noexceptpolicy for SD-9 (throws nothing) - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- P3313R0について、§ 8.3.3 Bloatに議論を追加
- P3318R0について、§ 8.5.1 Security dangers of throwing exceptions while in an unknown stateに議論を追加
などです。
P3087R1 Make direct-initialization for enumeration types at least as permissive as direct-list-initializatio
スコープ付き列挙型の値の初期化時に、直接初期化を許可する提案。
以前の記事を参照
このリビジョンでの変更は
- 別の設計について議論
- 提案している設計の選択根拠を強化
などです。
提示された代替設計とこの提案の比較は次のようになります
| 設計オプション | std::byte b(0) |
std::byte b(-1) |
std::byte b(0.f) |
|---|---|---|---|
| 現状維持 | ❌ | ❌ | ❌ |
| リスト初期化と同等にする | ✅ | ❌ | ❌ |
| 特定の変換の制限 | ✅ | ✅ | ❌ |
| この提案 | ✅ | ✅ | ✅ |
この提案では非リスト直接初期化時の一貫しない挙動を修正しようとしており、列挙型の変換を安全に拡張することを目的としていないため、その観点からは他の選択肢は望ましくないとしています。また、実装品質の問題として、この提案で許可される変換で縮小変換が起こる場合に警告を発することもできます。
この提案はEWGのレビューにおいてこれ以上追及しないことが決定されました。
P3094R3 std::basic_fixed_string
NTTPとして使用可能なコンパイル時文字列型であるstd::basic_fixed_stringの提案。
以前の記事を参照
- P3094R0
std::basic_fixed_string- WG21月次提案文書を眺める(2024年02月) - P3094R1
std::basic_fixed_string- WG21月次提案文書を眺める(2024年04月) - P3094R2
std::basic_fixed_string- WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- 文字のリスト(
{...}ではなく)を取るコンストラクタの動機を追記 - 容量関連の操作を修正し、
std::integral_constantを適切に使用するようになった - 非メンバ
swapを使用する根拠を追記 - Annex Cエントリを追加
- その他文言の改善
などです。
P3096R2 Function Parameter Reflection in Reflection for C++26
C++26に向けた静的リフレクションに対して、関数仮引数に対するリフレクションを追加する提案。
以前の記事を参照
- P3096R0 Function Parameter Reflection in Reflection for C++26 - WG21月次提案文書を眺める(2024年02月)
- P3096R1 Function Parameter Reflection in Reflection for C++26 - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- EWGでの投票結果を追加
- 提案する文言の改善
template forの代わりにexpandを使用する例を追加- 実装経験のメモを追加
などです。
P3124R0 2024-02 Library Evolution Poll Outcomes
2024年2月に行われたLEWGの投票の結果。
次の5つの提案が投票にかけられ、最初の4つはC++26を目指してLWGに転送されました。
- P3019R6 Vocabulary Types for Composite Class Design
- P2872R2 Remove wstring_convert From C++26
- P2875R3 Undeprecate polymorphic_allocator::destroy for C++26
- P3029R0 Better mdspan’s CTAD
- P3109R0 A plan for std::execution for C++26
最後のものは作業予定を承認した形になります。
賛否の票数や投票に当たって寄せられたコメントが記載されています。
P3137R2 views::to_input
入力の範囲をinput_rangeに弱めるRangeアダプタ、views::inputの提案。
以前の記事を参照
- P3137R0
views::to_input- WG21月次提案文書を眺める(2024年02月) - P3137R1
views::to_input- WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は、機能テストマクロを追加したことです。
P3138R2 views::cache_last
入力範囲の現在の要素をキャッシュするRangeアダプタ、views::cache_lastの提案。
以前の記事を参照
- P3138R0
views::cache_last- WG21月次提案文書を眺める(2024年02月) - P3138R1
views::cache_last- WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は、SG1からのフィードバックに従いconstメンバ関数のスレッドセーフ性保証の例外の追加をいったん削除したことと、機能テストマクロを追加したことです。
この提案では[res.on.data.races]の条項に対して提案しているviews::cache_lastを例外として追加しようとしていましたが、その文言にはすでに"unless otherwise specified"という文言によって例外が考慮されています。しかし、どのようにしてそれを個別のライブラリ機能(特にテンプレート)に適用すべきかが明確ではなく、これはこの提案ではなくLWGのIssueとして対処されることになりました。
P3144R1 Deprecate Delete of Incomplete Class Type
↓
P3144R2 Deleting a Pointer to an Incomplete Type Should be Ill-formed
不完全型のポインタに対するdeleteを非推奨にする提案。
以前の記事を参照
R1での変更は
- 2024/05/15のEWGレビューの記録を追加
- 推奨されるソリューションはill-formedであり、非推奨ではないことを明確化
- 推奨されるソリューションについての文言を追加
- C++26をターゲットとしてCWGに転送
このリビジョンでの変更は
- 採用されたソリューションを反映するようにタイトル変更
- CWGレビューの記録を追加
- P2795の最終リビジョンへ参照を更新
などです。
このリビジョンで不完全型のポインタに対するdeleteについて最終的に選択されたソリューションは、非推奨やEBとするものではなく、C++26で即座にill-formedとすることです。
この提案は2024年6月の全体会議で承認され、C++26に採択されています。
P3149R4 async_scope -- Creating scopes for non-sequential concurrency
↓
P3149R5 async_scope -- Creating scopes for non-sequential concurrency
P2300のExecutorライブラリについて、並列数が実行時に決まる場合の並行処理のハンドリングを安全に行うための機能を提供する提案。
以前の記事を参照
- P3149R0 async_scope -- Creating scopes for non-sequential concurrency - WG21月次提案文書を眺める(2024年02月)
- P3149R2 async_scope -- Creating scopes for non-sequential concurrency - WG21月次提案文書を眺める(2024年04月)
- P3149R3 async_scope -- Creating scopes for non-sequential concurrency - WG21月次提案文書を眺める(2024年05月)
R4での変更は
spawn_future()の呼び出し元は、オプションの環境引数からストップトークンを提供できるようにした[[nodiscard]]を削除simple_counting_scope::token::token()とcounting_scope::token::token()をexplicitかつ説明専用にする- 冗長な
async_scopeコンセプトを削除 let_with_async_scopeの最後の名残を取り除いた- 新しいSpecificationセクションにいくつか文言を追加
このリビジョンでの変更は
- ネストした
senderのoperation stateはスコープの参照カウントを減らす前に、子のoperation stateはを破棄する必要がある事を明確化 - 命名に関する議論を追加
- メモリアロケータの生存期間に関する懸念と、それを解決するためのいくつかのオプションについて説明を追加
などです。
P3161R2 Unified integer overflow arithmetic
オーバーフローを処理可能な整数演算の提案。
以前の記事を参照
このリビジョンでの変更は、would_cast_modify()を削除して既存のin_range()に変更し、いくつかの例を更新したことです。
P3164R1 Improving diagnostics for sender expressions
↓
P3164R2 Improving diagnostics for sender expressions
提案中のExecutorライブラリにおいて、senderチェーンのエラーを早期に報告するようにする提案。
以前の記事を参照
R1での変更は
transform_completion_signaturesの仕様を変更して、completion_signatures<>の特殊化ではない型を伝播する- カスタマイゼーションポイント
let_value, let_error, let_stoppedについては、呼び出し可能オブジェクトの可能な戻り値型が全てsenderであることを必須にする senderを積極的にconnectするアルゴリズムでは、RequiresをMandatesに変更
などです。
このリビジョンでの変更は
completion_signatures_of_t<Sndr, Env...>のsender_in<Sndr, Env...>制約を削除- 最後の手段として、
get_completion_signatures(sndr, env)をget_completion_signatures(sndr)へディスパッチするように指定 - 実装者が
senderアダプタアルゴリズムの完了シグネチャを利用して型エラーを伝播することを奨励する get_completion_signaturesから返される型がcompletion_signatures<>の特殊化ではない場合はエラーを表すものと推論する設計の決定に関する議論を追加
などです。
P3168R2 Give std::optional Range Support
std::optionalをrangeにする提案。
以前の記事を参照
このリビジョンでの変更は
- LEWG Feedback#P3168R1 サブセクションにLEWG投票結果を記載
- Implementation experience#Beman.Optional26 サブセクションに実装経験について追記
などです。
この提案は2024年6月の全体会議で承認され、C++26に向けて採択されています。
P3175R3 Reconsidering the std::execution::on algorithm
P2300のstd::execution::onアルゴリズムの命名について再考する提案。
以前の記事を参照
- P3175R0 Reconsidering the
std::execution::onalgorithm - WG21月次提案文書を眺める(2024年04月) - P3175R1 Reconsidering the
std::execution::onalgorithm - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
onアルゴリズムに標準タグ型を再度付加start_onとcontinue_onの名前をそれぞれ、starts_onとcontinues_onに変更onの2引数の場合の仕様のバグを修正get_scheduler(rcvr)をget_scheduler(get_env(rcvr))に置き換え
- [exec.on]/p1の
onの2つの形式の説明を改善 - 説明専用型
none-suchをnot-a-schedulerに変更 - LEWGが
onのカスタマイズに関する意味論制約を別の方法で指定することを望んでいるという編集メモを追加
などです。
この提案は2024年6月の全体会議で承認され、C++26に向けて採択されています。
P3178R0 Retrieval of Exception Information
↓
P3178R1 Retrieval of Exception Information
現在投げられている例外もしくはexception_ptrから例外オブジェクトの情報を取得する関数の提案。
catch(...)の形のcatch節においては、例外オブジェクトの型は全く分からず、そのtype_infoを得る方法がありません。また、exception_ptrを取得したとしても、そのexception_ptrが参照している例外オブジェクトの型情報を得ることはできません。さらにどちらの場合も、例外オブジェクトのアドレスを取得することもできません。
例えば、C++のプログラムは共有ライブラリと動的にリンクされて利用されることがありますが、そのような動的ライブラリではしばしば、その例外仕様についてきちんと記述されていないことがあります。さらには、LoadLibraryやdlopenなどによって事前情報のないライブラリと動的にリンクされることもあります。
このような場合に、共有ライブラリの関数を呼び出すメインのプログラムでは、共有ライブラリ内からの例外送出に対応するために、例えば次のように例外を処理します
#include <exception> // exception, exception_ptr #include <new> // bad_alloc #include <typeinfo> // typeid, type_info extern void SomeLibraryFunction(void) noexcept(false); int main(void) { try { SomeLibraryFunction(); } catch(std::bad_alloc const&) { // メモリが足りない場合 } catch(std::exception const &e) { std::type_info const &ti = typeid(e); // std::exceptionはポリモルフィックなクラスなので、そのtypeid()は派生先の型情報を提供する } catch(...) { std::exception_ptr const p = std::current_exception(); // 例外オブジェクトへのポインタは取得できるものの、何が送出されてきたのか分からない・・・ } }
この提案はまず、このような場合に現在送出されている例外オブジェクトの型情報(std::type_info)を取得するライブラリ関数を提供することを提案しています。
catch(...) { std::type_info const &ti = std::exception_typeid(); // 送出されている例外オブジェクトの型情報を得る // あるいは、exception_ptrから取得する std::exception_ptr const p = std::current_exception(); std::type_info const &ti = std::exception_typeid(p); }
type_infoから取得できる型名は名前マングリングされているものではあるものの、特定の関数やクラス名はそのまま含まれているため、文字列検索などでエラーについての手掛かりを得ることができます。
また、共有ライブラリの別のユースケースとして、サードパーティプラグインのサポートがあります。このような場合、予め共有ライブラリが提供する関数に制約が課されており、そのうちの一つとしてプラグイン(の共有ライブラリ)から送出されうる例外のtype_info配列を返す次のPlugin_GetExceptions()のような関数があります
std::type_info const *const *Plugin_GetExceptions();
プラグインをサポートするメインのプログラムでは、プラグインのロード時にこの配列を取得しておき、プラグイン処理から例外が送出されてきた場合にこの配列を参照することで、プログラムが同じようにエクスポートしている例外ハンドラを呼び出すなど、例外に特化したエラーハンドリングが可能になります。
catch(...) { // 送出されてきた例外のtype_infoを取得 std::type_info const &ti = std::exception_typeid(); // 候補例外リストを検索し、適切なハンドラを呼び出す if ( nullptr != plugin_exceptions.find(&ti) ) { void (*const handler)(void*) = handlers[ std::type_index(ti) ]; // プラグインの提供するハンドラに例外オブジェクトへのアドレスを渡す handler( std::exception_object() ); } }
このような場合に、送出されてきた例外オブジェクトのアドレスは、メインのプログラム側では有効に使用できないかもしれませんが、プラグイン内では有効活用できる可能性があり、それを取得してハンドラにコールバックするとより便利です。しかし現在のところ、このように現在送出されている例外オブジェクトのアドレスを取得するポータブルで安全な方法はありません。
この提案ではそれを、std::exception_object()によって取得可能にします。
この提案で提供される関数の宣言は次のようになります
// <exception>内 namespace std { type_info const &exception_typeid() noexcept; type_info const &exception_typeid(exception_ptr const &p) noexcept; void *exception_object() noexcept; void *exception_object(exception_ptr const &p) noexcept; }
exception_typeid()は例外オブジェクトの型情報(type_info)を取得するもので、exception_object()は例外オブジェクトのアドレスを取得するものです。どちらも、引数無しのものはcatch(...)節内で処理中の例外について取得し、exception_ptrを引数に取るものはそのexception_ptrが参照する例外オブジェクトについて取得します。
この提案ではさらに、プラットフォーム固有の例外事情(WindowsのSEHやPOSIXのForced unwindingなど)にもこれらの機能を対応可能にすることを提案しています。
SEHは通常C++の例外ハンドラではハンドルできませんが、/EHaオプションを指定することでcatch(...)節でハンドル可能になります。このときcurrent_exception()は有効なexception_ptrを返すものの、そのtype_infoは利用できません。この場合、exception_typeid()の戻り値をtypeid(void)やtypeid(_s__se_exception)のような特別な型情報を返し、SEH例外オブジェクトの実体はunsigned intなのでexception_object()の戻り値はそのアドレスを返すことを推奨しています。
例外が送出されていないにもかかわらずスタックの巻き戻しが起こるforced unwindingの場合でもcatch(...)節でハンドルすることができますが、この場合、exception_typeid()の戻り値をtypeid(void)やtypeid(abi::__forced_unwind)のような特別な型情報を返し、またexception_object()の戻り値をnullptrにすることを推奨しています。
P3179R2 C++ parallel range algorithms
RangeアルゴリズムをExecutionPolicyに対応させる提案。
以前の記事を参照
- P3179R0 C+ parallel range algorithms - WG21月次提案文書を眺める(2024年04月)
- P3179R1 C+ parallel range algorithms - WG21月次提案文書を眺める(2024年05月)
このリビジョンでの変更は
- シリアルRangeアルゴリズムと非Rangeの並列アルゴリズムの提案されている違いをまとめた
- 並列Rangeアルゴリズムで複数の範囲を入力に取るものは、入力のうち1つだけが境界あり(
sized_range)であればよいように緩和- 残りの入力は
sizedである必要は無くなった
- 残りの入力は
- 出力範囲を取る既存のRangeアルゴリズムの一覧を追加
- 出力に範囲を使用するための引数と緩和策を更新
random_access_rangeをサポートする引数を追加- 提案された設計と一致するように例示している
for_eachのシグネチャを更新
などです。
P3182R1 Add container pop methods that return the popped value
標準ライブラリのシーケンスコンテナとコンテナアダプタに、値を取り出して返す関数を追加する提案。
以前の記事を参照
このリビジョンでの変更は
- コンテナアダプタが内部で使用するシーケンスコンテナに対して変更を行うようにした
- 例外安全性に関する説明を拡張
- その他の設計上の決定に関する説名を追加
- この提案による恩恵を受けうるコードの量に関する見積もりを追記
- 関数名の変更
などです。
この提案では、提案する関数名が.pop_front_value()と.pop_back_value()の2つになり、これらの関数はコンテナアダプタだけではなくシーケンスコンテナ(std::vector, std::deque, std::list, std::forward_listとstd::string)にも追加(片方しかないものもある)され、コンテナアダプタの関数は内部コンテナの関数を呼び出して処理を行うようになりました。
P3212R0 The contract of sort()
std::ranges::sortの関数契約をP2900の契約プログラミング機能で記述してみた実験の報告書。
使用したstd::ranges::sortはイテレータペアを受け取るオーバーロードで、次のような宣言となるものです
template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less, class Proj = identity> requires sortable<I, Comp, Proj> constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {});
まず現在でも、コンセプトによって関数契約の一部が表現されて指定されています。コンセプトには構文要件と意味論要件があり、構文要件はコンパイラによってチェックされていますが、意味論要件は呼び出し側が満たすべきものです。
また、sortableコンセプトは次の概ね3つのコンセプトからなる少し複雑なコンセプトです
regular_invocablestrict_weak_orderpermutable
これらは、比較関数compに対して範囲[first, last)が等しさを保持することを要求しています。
次に、範囲に対する一般的な要件として、[first, last)が有効な範囲である必要があります。さらに、sortの実行中にこの範囲が別の所から変更されないことも呼び出し側が保証する必要があります。
最後に、sort固有の要件(事後条件)があります
- 結果の範囲は
compとprojに関してソートされる - 出力範囲は入力範囲の順列となる
N = last - firstとして、compとprojの呼び出し回数はO(N log N)
これらの要件をP2900の機能によってコードにエンコードすることを考えます。
しかしまず、特定の型があるコンセプトのモデルとなっているかを確認することは必ずしも可能ではありません。ムーブによって値が実際にムーブされるかどうかをチェックすることも型がコピーや比較を実装していないとできませんが、sort()は必ずしもそれを求めておらず、契約チェックのために新しいコンセプトを追加するのは正しい行いではないでしょう。
提供された述語がstrict_weak_orderコンセプトを満たすかどうかはO(N^2)ではあるものの評価可能です。ただし、このチェックを追加するとsort()の計算量要件が破られます。
このような要件を標準で指定するためには次の2つの選択肢が考えられます
- 標準ライブラリの規定で関数に契約注釈が指定されていても、実装は必ずしもそれに倣う必要が無いことを許可する
- 実行時に評価されないアサーションを表すラベルを導入する
- 以前これは
auditと呼ばれていた
- 以前これは
auditで指定するとすると次のようになります
template<random_access_iterator I, sentinel_for<I> S, class Comp, class Proj> requires sortable<I, Comp, Proj> constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {}) pre audit(is_strict_weak_order(first, last, comp, proj));
同様に、等しさの保持をチェックすることもできません。各引数のペアについてcompを何回か呼び出して同じ値を返すかチェックすることはできますが、前述のようにここではoperator==が必ずしも使用可能ではありません。また、何回チェックしたとしても、それが常に同じ値を返すことの保証にはなりません。
operator==が使用可能な場合にのみ事前条件がチェックされる、という構文をpre() requiresであらわすと、この要件は次のように書けます
pre (maybe_is_equality_preserving(first, last, comp, proj)) requires equality_comparable<typename iterator_traits<I>value_type>;
入力の範囲が有効であるかどうかも、厳密にチェックすることはできません。ただし、形式的に記述することはできる(範囲を一回何もせずにイテレーションする)ので、そのような述語を使用して契約を記述することはできます。
このような形式的にしか表現できない(実質的なチェックを行えない)述語を使用して契約条件を記述することには一定の価値があります。例えば、ユーザーとIDE等ツールはそれを読み取ることができます。そして、ツールはその情報を各種分析に使用できます。
このような種類の契約アサーションを表現するためには契約注釈もしくは関数宣言に対してそれを表明する新しい宣言を追加する必要があります
template<random_access_iterator I, sentinel_for<I> S> axiom is_valid_range(I first, S last); // 宣言のみで定義されない template<random_access_iterator I, sentinel_for<I> S, class Comp, class Proj> requires sortable<I, Comp, Proj> constexpr I ranges::sort(I first, S last, Comp comp = {}, Proj proj = {}) pre axiom(is_valid_range(first, last)); // axiom事前条件、評価されない
最後にsortの事後条件特に「出力範囲は入力範囲の順列となる」という条件のチェックを行うためには、入力範囲をコピーして保存しておいて、関数の終了までそれを保持する必要があります。これを行える構文は今は無いので、例えばラムダキャプチャのような構文を使用してそれを行うことにすると、次のように記述できます
template<random_access_iterator I, sentinel_for<I> S, class Comp, class Proj> requires sortable<I, Comp, Proj> constexpr I ranges::sort(const I first, const S last, Comp comp = {}, Proj proj = {}) post audit [in = vector(first, last)] (is_permutation(first, last, in.begin(), in.end()));
ここで範囲をキャプチャするのにstd::vectorを選択しましたがこれによってsort()が特定のコンテナに依存してしまうことになります。さらに、これはstd::vectorの構築という元の文章で指定された契約以上のものを表しています。
これはまた副作用を伴う術語にもなっており、この事後条件はメモリを確保し、O(N)でコピーし、例外送出の可能性もあります。さらに、キャプチャ動作は関数開始時に発生し、このチェックはO(N^2)の計算量となります。このような事後条件は静的分析で活用されるのは想像しづらいものがあります。
個別に挙げてきたアサーションを全て組み合わせると次のようになります
template<random_access_iterator I, sentinel_for<I> S, class Comp, class Proj> requires sortable<I, Comp, Proj> constexpr I ranges::sort(const I first, const S last, Comp comp = {}, Proj proj = {}) pre axiom (is_valid_range(first, last)) pre audit (is_strict_weak_order(first, last, comp, proj)) pre audit (maybe_is_equality_preserving(first, last, comp, proj)) requires equality_comparable<typename iterator_traits<I>value_type> post (ranges::is_sorted(first, last, comp, proj)) post audit [in = vector(first, last)] (is_permutation(first, last, in.begin(), in.end()));
これらのアサーションのうち、現在のP2900で表現可能なのは1つだけです。
この経験から、標準ライブラリ機能に契約アサーションを追加する場合に、その目標は何なのか?という問いを行う必要がある事がわかります。答えは次の2つのどちらかでしょう
- ツールに契約違反検出に有効なあらゆるヒントを提供する
- 型・コンセプト・指定子が表現できていない契約の部分をコードで記述する
先程の宣言は1の目標を満たしていますが、2の目標のためには少し過剰です。既存コンセプトが表現している意味論要件のチェックを取り除くと、幾分宣言がスリムになります
template<random_access_iterator I, sentinel_for<I> S, class Comp, class Proj> requires sortable<I, Comp, Proj> constexpr I ranges::sort(const I first, const S last, Comp comp = {}, Proj proj = {}) pre axiom (is_valid_range(first, last)) post (ranges::is_sorted(first, last, comp, proj)) post audit [in = vector(first, last)] (is_permutation(first, last, in.begin(), in.end()));
なお、この文書は実験報告書であり何らかの提案をするものではありません。
P3223R1 Making std::istream::ignore less surprising
istream::ignore()の第二引数に負の値を与えた場合の動作を修正する提案。
以前の記事を参照
このリビジョンでの変更は
to_int_typeに対する暗黙の仮定を避けるための議論を拡張- 提案している新しいオーバーロードにConstraintsを追加
std::basic_istreamではなくstd::istreamに特化したものになるようにタイトルを調整
などです。
P3235R1 std::print more types faster with less memory
↓
P3235R2 std::print more types faster with less memory
↓
P3235R3 std::print more types faster with less memory
std::printの効率的な実装をより拡大して適用する提案。
以前の記事を参照
R1での変更は
rangeのフォーマッタにおけるレンダリングの問題を修正
R2での変更は
- LEWGからのフィードバックに従い、
rangeのフォーマッタを対象にしないようにした
このリビジョンでの変更は
- 機能テストマクロ
__cpp_lib_printを更新するための手順を追加 <chrono>のdration型のRepテンプレートパラメータはユーザー定義の算術型likeな型になる可能性があるため、Repがカスタマイズされているかに応じて条件付きで(<chrono>のdration型の)オプトインを有効化するようにした
などです。
この提案C++23へのDRとして、2024年6月の全体会議で採択されています。
P3245R1 Allow [[nodiscard]] in type alias declarations
[[nodiscard]] 属性を型エイリアス宣言で使用できるようにする提案。
以前の記事を参照
このリビジョンでの変更は
- 2024年6月の全体会議でのEWGIレビューにおける投票結果を追加
- モチベーションを拡張
- コーナーケースの例を追加
などです。
P3248R1 Require [u]intptr_t
(u)intptr_tを必須にする提案。
以前の記事を参照
このリビジョンでの変更は
- "Design"セクションにCとC++間のヘッダファイルの不一致に関するセクションを追加
- [u]intptr_tを要求するC言語の取り組みに関するコンテキストを追加
- Memory Taggingに関する説明を追加
- [u]intptr_tのC23仕様について追記
- 準拠実装と非準拠実装への影響分析を追加
などです。
P3255R1 Expose whether atomic notifying operations are lock-free
std::atomicの通知・待機系関数がロックフリーとは限らない場合がある問題について修正する提案。
以前の記事を参照
このリビジョンでの変更は
wait_is_signal_safe、wait_is_always_signal_safe、std::atomic_is_signal_safeを追加- その他文言の修正
などです。
このリビジョンでは、以前の3つの提案に加えて
std::atomic_flag、std::atomic、std::atomic_refにメンバ関数.wait_is_signal_safe()とメンバ定数notify_is_always_signal_safeを追加し、std::atomic_notify_is_signal_safe()フリー関数を追加- これらの関数および定数の値は、対応するアトミック型の待機操作がUBなしでシグナルハンドラ内で使用できるかを表す
bool値
- これらの関数および定数の値は、対応するアトミック型の待機操作がUBなしでシグナルハンドラ内で使用できるかを表す
が追加されました。
P3265R2 Ship Contracts in a TS
↓
P3265R3 Ship Contracts in a TS
契約プログラミング機能をまずTSとして出荷すべき、とする提案。
以前の記事を参照
変更点が明確化されていないのでこのリビジョンでの変更はよくわかりませんが、DG's questions from P4000というセクションが追加されており、そこではTSを発行するにあたって収集すべき質問リストが提示されているようです。
などです。
P3288R1 std::elide
↓
P3288R2 std::elide
↓
P3288R3 std::elide
コピーもムーブできないクラス型のprvalueの生成を遅延するライブラリ機能の提案。
以前の記事を参照
R1での変更は
std::elideクラスをfinal指定しない- コンストラクタに1引数しかない場合にテンプレートのインスタンス化が失敗する
- テンプレートのインスタンス化は
trueと評価されるtypedefタグの存在によって失敗する
R2での変更は
optional/varinatに.emplace_invoke()を追加する代替案を追記std::elideは定数式で使用可能std::construct_at()は配置newの代替として追加されており、定数式で使用できるTはコピー構築可能である必要があるため、std::anyの例を削除boost::static_vectorの例を追加- このクラスを検出する入れ子型名を
tag_elideに変更
このリビジョンでの変更は
- 関数ポインタと非常に小さなトリビアルな関数の最適化により、参照
tupleではなくラムダを使用するように実装を変更 - 1引数コンストラクタテンプレートで
std::elideを推論したい場合のために、std::elide_c1を使用する - eliderの連鎖は
operator()で可能になった tag_elideはtag_tempfail_ctor_soleparamにリネームstd::elide_c1によって不要になったため、std::elideから派生する例を削除
などです。
素直なstd::elideの実装だと、次のようにコンストラクタテンプレート(特に一引数のもの)において変換が起こらずにstd::elideが直接観測されてしまいます
class AwkwardClass { std::mutex m; // cannot move, cannot copy public: template<typename T> AwkwardClass(T &&arg) { cout << "In constructor for AwkwardClass, \n" "type of T = " << typeid(T).name() << endl; } }; AwkwardClass ReturnAwkwardClass(int const arg) { return AwkwardClass(arg); } int main(int const argc, char **const argv) { std::optional<AwkwardClass> var; var.emplace( std::elide(ReturnAwkwardClass, -1) ); }
この例は次のような結果を出力します
In constructor for AwkwardClass, type of T = std::elide< AwkwardClass, AwkwardClass (&)(int), int&& >
理想的にはここでT = intになればいいのですがこれは困難なので、tag_tempfail_ctor_soleparamという入れ子型を使用して次のように回避することを提案しています
template<typename... Params> requires ( !( (1u==sizeof...(Params)) && (std::has_tag_tempfail_ctor_soleparam_true<Params> || ...) ) ) AwkwardClass(Params&&... arg) { ( std::cout << "In constructor for AwkwardClass, type of T = " << typeid(Params).name() << std::endl, ... ); }
既存の標準ライブラリ型にこれを追加して回るのは大変なので、この提案ではコア言語を変更してどのクラスのコンストラクタもstd::elideの特殊化をその唯一の引数として持てないようにすることを提案しています。実装的には上記のような制約を書くコンストラクタに追加することになります。
P3290R1 Integrating Existing Assertions With Contracts
既存のアサーション機構に契約プログラミング機能を統合する提案。
以前の記事を参照
このリビジョンでの変更は
- ライブラリAPIに
source_locationオーバーロードを追加- 違反ハンドラの直接呼び出しを行うAPIに対して追加
assertマクロの動作を変更するための制御マクロを追加partial_contract_assertの提案を削除
などです。
P3294R1 Code Injection with Token Sequences
トークンシーケンスを用いてコード注入によるコンパイル時コード生成機能の提案。
以前の記事を参照
このリビジョンでの変更は
- トークンシーケンスを導入する構文を
^{...}に変更(以前は@tokens{...}) - トークンシーケンス作成時の外部環境のキャプチャ構文(interpolator)を変更
declare [: e :]を削除inject()をqueue_injection()に変更- 提案の多くを実装し、例を実行したリンクを追記
- 衛生的マクロの引数型を
std::meta::infoに変更
などです。
以前のサンプルコードをこのリビジョンで改めて書き直すと次のようになります
std::tupleのストレージを定義する例
template <class... Ts> struct Tuple { consteval { // パラメータパックTsから個別のmeta::info型を取得し保存 std::meta::info types[] = {^Ts...}; // Tsの型ごとにメンバ変数を宣言する for (size_t i = 0; i != sizeof...(Ts); ++i) { queue_injection(^{ [[no_unique_address]] [:\(types[i]):] \id("_", i); }); } /* Tsの型名をTi(iは数値)とすると [[no_unique_address]] Ti _i; のようなメンバ宣言がTupleクラスの定義に注入される */ } };
std::enable_ifを定義する例
template <bool B, class T=void> struct enable_if { consteval { // Bがtrueの場合にのみ、`using type = T;`を注入する if (B) { queue_injection(^{ using type = T; }); } } };
簡単なプロパティ機能を注入する関数を定義する例
consteval auto property(std::meta::info type, std::string_view name) -> void { // メンバ変数名のトークンシーケンスを作成 auto member = ^{ \id("m_"sv, name) }; // メンバ変数宣言を注入 // 型名をTとすると // T m_name; // のような宣言が注入される queue_injection(^{ [:\(type):] \tokens(member); }); // ゲッター関数宣言を注入 // 型名をTとすると // auto get_name() -> T const& { // return m_name; // } // のような宣言が注入される queue_injection(^{ auto \id("get_"sv, name)() -> [:\(type):] const& { return \tokens(member); } }); // ゲッター関数宣言を注入 // 型名をTとすると // auto set_name(T const& x) -> void { // m_name = x; // } // のような宣言が注入される queue_injection(^{ auto \id("set_"sv, name)(typename [:\(type):] const& x) -> void { \tokens(member) = x; } }); } // 使用例 struct Book { consteval { property(^std::string, "title"); property(^std::string, "author"); } }; int main() { Book b: b.set_author("太宰治"); b.set_title("人間失格"); std::string author = b.get_author(); std::string title = b.get_title(); }
アサーションマクロの例
consteval auto assert_eq(@tokens a, @tokens b) -> info { return @tokens { do { // aの式文字列と式の評価結果を取得 auto sa = $eval(stringify(a)); auto va = $eval(a); // bの式文字列と式の評価結果を取得 auto sb = $eval(stringify(b)); auto vb = $eval(b); if (not (va == vb)) { // アサートが失敗した場合、それぞれの式の評価結果と場所を出力して終了させる std::println( stderr, "{} ({}) == {} ({}) failed at {}", sa, va, sb, vb, $eval(source_location_of(a))); std::abort(); } } while (false); }; } consteval auto assert_eq(meta::info a, meta::info b) -> meta::info { return ^{ do { // aの式文字列と式の評価結果を取得 auto sa = \(stringify(a)); auto va = \tokens(a); // bの式文字列と式の評価結果を取得 auto sb = \(stringify(b)); auto vb = \tokens(b); if (not (va == vb)) { // アサートが失敗した場合、それぞれの式の評価結果と場所を出力して終了させる std::println( stderr, "{} ({}) == {} ({}) failed at {}", sa, va, sb, vb, \(source_location_of(a))); std::abort(); } } while (false); }; }
// こう書くと assert_eq!(42, factorial(3)); // こう展開される do { auto sa = "42"; auto va = 42; auto sb = "factorial(3)"; auto vb = factorial(3); if (not (va == vb)) { std::println( stderr, "{} ({}) == {} ({}) failed at {}", sa, va, sb, vb, /* some source location */); std::abort(); } } while(false);
P3296R1 let_with_async_scope
提案中のcounting_scopeの問題を修正する提案。
以前の記事を参照
このリビジョンでの変更は明確ではないですが、P3149R3の変更を適用してサンプルコードや一部の文書を修正したことの様です。
P3297R1 C++26 Needs Contract Checking
以前の記事を参照
このリビジョンでの変更は明確ではないですが、一部の文章が修正・加筆されているほか、"Who Watches the Watcher?"セクションが追加され、そこでは契約条件式にUBが含まれている場合の影響について論じています。
"Who Watches the Watcher?"セクションでは、契約条件式にUBが含まれてしまったとしても現状より悪くなることはなく、安全性とはシステム全体の性質であるためそこの責任はWG21にはなく、全ての契約条件式からUBを取り除く実用的な方法を待つ機会費用が早期に導入された場合のメリットを大きく上回るとしています。
SG23におけるこの提案のレビューおよび投票においては、C++26で何もしないよりはここで提案されているようにP2900をさらに弱めたものを導入したほうが良い、という方向性に合意がされています(ただし反対票が無いわけではありませんが)。
P3303R1 Fixing Lazy Sender Algorithm Customization
P2999の提案の欠けていた部分を埋める提案。
以前の記事を参照
このリビジョンでの変更は、transform_senderに渡されるドメインの型を計算するときにsndr式が評価されないようにconnectとget_completion_signaturesの仕様を調整したことです。
この提案は2024年7月に行われた全体会議で承認され、C++26WDに適用されています。
P3309R1 constexpr atomic and atomic_ref
std::atomic/stomic_refをconstexpr化する提案。
以前の記事を参照
このリビジョンでの変更は
- SG1の要求により、
wait()と通知系関数をconstexpr化し、それにより文言を修正 - 実装リンクの更新
などです。
P3310R1 Solving partial ordering issues introduced by P0522R0
↓
P3310R2 Solving partial ordering issues introduced by P0522R0
P0552R0の影響を緩和するための提案。
以前の記事を参照
R1での変更は
- 問題1
- クラステンプレートのデフォルト引数を推論することの結果をさらに調査し、一貫して動作するようにルールを調整
- パックのデフォルト引数を推論することの結果をさらに調査
- 一貫性のない推論の例をさらに調査
- 問題2
- 現在の振る舞いの意味や価値と、この提案のものを混在させた場合の影響に関する説明を追加
このリビジョンでの変更は、問題1に関して解決策の表記と説明を改善したことです。
P3314R0 2024-07 Library Evolution Polls
2024年7月に行われる予定の、LEWGにおける投票の予定。
次の提案が投票にかけられる予定です
- P2835R4 Expose std::atomic_ref’s object address
- P3016R3 Resolve inconsistencies in begin/end for valarray and braced initializer lists
これはC++26に向けてLWGに転送するための投票です。
P3319R1 Add an iota object for simd (and more)
std::simdオブジェクト(SIMDレジスタ)を連番の値で初期化するAPIの提案。
以前の記事を参照
このリビジョンでの変更は
- 動機付けの説明に例を追加
- “Generalization”セクションを拡張して、概要を説明するのではなく機能を詳細に説明する
- 初期値とステップに関する説明を追加
- 既存の
iotaアルゴリズム/viewを使用しても、std::simdのユースケースでは機能しないか十分ではない理由を説明 iota_vが適切な名前である理由を説明
などです。
P3321R0 Contracts Interaction With Tooling
P2900の契約プログラミング機能の実装定義とされている部分について、その範囲や意義を説明する文書。
P2900で提案されている現在のC++ Contracts仕様は一見すると、多くの部分が実装定義とされており標準では何も指定していないように見えます。この文書はP2900の仕様が実装定義としている部分をリストアップしそれが意図している自由度を説明するとともに、推奨する実装ベースラインを定義しようとするものです。
P2900が実際に実装定義としているのは次の2か所です
- 契約注釈が評価されるかどうか、およびいつ・どのように評価されるのか、について
- 評価は繰り返されることがある
- 結果が確定的である場合は評価を省略できる
- 評価は、
ignore,observe,enforce, あるいはquick_enforceセマンティクスによって起こる - ここの実装定義はユーザーによって制御されるもの
observeもしくはenforceセマンティクスによって評価された契約注釈で違反が検出されると、ユーザー定義の違反ハンドラが呼び出される- このハンドラは条件付きで置換可能で、プラットフォームによってデフォルトの実装が提供される
- プラットフォームは
enforceセマンティクスで評価された場合にプログラムを終了する方法などのセマンティクスの他の部分に加えて、contract_violationオブジェクトの作成と設定も担う - ここの実装定義はプラットフォームの実装自由度を確保するためのもの
P2900の仕様はC++ Contractsの最初のバージョンから、予想される実装アプローチのすべてが準拠した実装になるようにすることを最終目標として設計されています。
この実装定義とされている仕様に対して、実装戦略の自由度の範囲は次のようにグループ化されます
- 契約アサーションの評価場所とタイミング
- 契約アサーションの評価セマンティクスの選択方法
- 契約違反ハンドラの呼び出し方法
- 契約違反ハンドラを呼び出すには、生成されたコードが
std::contracts::contract_violationオブジェクトを作成するための情報を収集する必要がある - プラットフォームの共有ABIは、このプロセスを処理するための関数を提供する必要がある
- Itanium ABIでは、
_Contract_Violationデータ型と、関連情報にアクセスするためのアクセサー関数を提供することが提案されている
- 契約違反ハンドラを呼び出すには、生成されたコードが
- 契約違反ハンドラの置換可能性
- 実装は、契約違反ハンドラが置換可能かどうかを決定する必要がある
- 置換可能なハンドラは、ユーザーが環境での違反を軽減する方法に柔軟性を提供する
- 置換不可能なハンドラは、プログラムの動作に対するより厳格な保証を提供する
- 契約違反オブジェクトに配置される文字列
- デフォルトの契約違反ハンドラの動作
- デフォルトのハンドラは、診断出力を生成し、通常は復帰する必要がある
- 堅牢な実装では、破損した状態での安定性、過剰なロギングの防止、例外情報の組み込みなどの考慮事項を考慮する必要がある
- プログラムの終了方法
- 述語を省略できる場合
これらの実装戦略の自由度の範囲は移植性と柔軟性のバランスをとるように設計されており、P2900で実装定義とされていることによって実装間で許容される唯一の違いとは、個々の契約アサーションを制御できる粒度と柔軟性の程度であり、それ以上ではありません。
この様な実装戦略の自由度は、C++ Contractsが幅広いプラットフォームとユースケースに適応できることを保証します。 開発者は、すべての準拠実装で動作するソフトウェアを安全に記述でき、ベンダーは単純な実装から始めて、必要に応じてより堅牢なニーズをサポートするように進化できます。
そして、この文書ではこれらの実装自由度毎に実装の推奨ベースラインを提案しています
- 契約アサーションの評価場所とタイミング
- 呼び出し元側のチェックは各呼び出し元側で行い、呼び出し先のチェックは関数本体で行うことを推奨
- 呼び出し元と呼び出し先のチェックが同じ(通常の関数呼び出しの)場合は、呼び出し元側のチェックはデフォルトでignoreセマンティクスで評価されるべき
- 呼び出し元側と呼び出し先のチェックが異なる可能性のある仮想ディスパッチの場合は、呼び出し元側と関数本体の両方で設定されたセマンティクスで評価を行うことを推奨
- 通常の関数呼び出しにおける呼び出し先でのチェックを呼び出し元側に切り替える設定パラメータを提供することも推奨
- 呼び出し元側のチェックは各呼び出し元側で行い、呼び出し先のチェックは関数本体で行うことを推奨
- 契約アサーションの評価セマンティクスの選択方法
- プラットフォームは、翻訳単位ごとおよび契約アサーションごとの契約アサーションの設定を可能にする標準のフラグセットをサポートすることを推奨
- 翻訳単位ごとの設定には、少なくとも明示的な評価セマンティクスの指定を含める必要があるが、機密コードや信頼できないコードなど、より意味のある設定オプションに拡張できる必要がある
- 個々の契約アサーションの設定は、グローバルに設定できるのと同じパラメータを設定できる、共通で定義された外部ファイル形式を介して実行する必要がある
- 翻訳単位ごとの設定には、少なくとも明示的な評価セマンティクスの指定を含める必要があるが、機密コードや信頼できないコードなど、より意味のある設定オプションに拡張できる必要がある
- リンカは、翻訳単位の設定方法に基づいてインライン関数定義を選択する設定をサポートするように更新する必要がある
- リンカに明示的に何も指定されていない場合、リンカは最も厳格なチェックを行う定義を選択する必要がある
- これは、ユーザーが特定の翻訳単位でenforceセマンティクスによる評価を要求した場合に、関数がインライン化されなかったためにリンカがより緩やかな定義を選択したという理由だけで、契約アサーションがenforceにならない事を回避するため
- 一部のビルドでは、アプリケーションのホットパスにオーバーヘッドが発生することを避けることを強く望むため、オーバーヘッドの少ないセマンティクスを選択するようにリンカに指示する設定も提供する必要がある
- リンク時のセマンティクスの選択は、複数の異なる契約構成で使用できる単一のバイナリライブラリの配布を可能にするために利用可能なオプションである必要がある
- コンパイル時およびリンク時の構成は、コンパイル時構成に適用されるすべての考慮事項が、サードパーティから提供されたバイナリを統合する場合にも同様に適用される可能性があるため、一貫性を持たせる必要がある
- 実行時のセマンティクスの選択は、選択された場合、何らかの形式のユーザー設定可能な関数を通過する必要があるが、これはコンパイラ固有のものである可能性がある
- プラットフォームは、翻訳単位ごとおよび契約アサーションごとの契約アサーションの設定を可能にする標準のフラグセットをサポートすることを推奨
- 契約違反ハンドラの呼び出し方法
- 契約違反オブジェクトに配置される文字列
- デフォルトの契約違反ハンドラの動作
- 推奨事項なし
- プログラムの終了方法
- 推奨事項なし
- 述語を省略できる場合
- 推奨事項なし
これらのことは必須ではなくあくまで推奨ですが、C++ Contracts実装におけるベースラインの動作となることを意図しています。
P3323R0 cv-qualified types in atomic and atomic_ref
std::atomicではCV修飾された型を使用できないこと、およびstd::atomic_refでは逆に使用できることを明確にする提案。
CWG Issue 2094の解決によって、トリビアルコピー可能な型のCV修飾されている型もトリビアルコピー可能であると判定されるようになりました(以前は常にそうならなかった)。
一方で、std::atomic<T>はTとして使用可能な条件の一つにis_trivially_copyable_v<T>がtrueであることがあり(他の条件はこれを満たしていれば多くの場合満たすことになる)、CWG Issue 2094解決後にstd::atomic<T>のTにCV修飾された型を指定した場合にどうなるかが問題となりました。
例えば、std::atomic<volatile int>やstd::atomic<const std::size_t>などは整数型のための部分特殊化が使用されない(CV非修飾のTに対してのみ特殊化されているため)という問題があり、浮動小数点数型についても同様です。同様に、std::atomic/std::atomic_refの多くの部分がTがCV非修飾であることを前提にしているため、どう動作すべきかが不明瞭になっています。
また、std::atomic_ref<const T>やstd::atomci_ref<volatile T>などには有用性がある(std::atomicとして構築されていないオブジェクトをアトミックアクセスし、なおかつ読み取り専用やvolatileで使用する)可能性があるものの、こちらもTがCV修飾を考慮していないことでどう動作するかが不透明です。
この提案は、CV修飾されたTについて、std::atomicでは使用を禁止し、std::atomic_refでは使用可能なように規定しなおす提案です。
std::atomic<T>の場合、Tに対する制約としてsame_as<T, remove_cv_t<T>>がtrueであることを要求するようになります。volatileの場合はvolatile std::atomic<T>でより良くサポートされているためそれも禁止されます。
std::atomic_ref<T>の場合はCV修飾を受け入れるもののstd::atomic_ref<volatile T>特殊化がサポートされるのはロックフリーの場合のみとし、std::atomic_ref<const T>特殊化においては可能な操作を読み取りのみに制限します。
- CWG Issue 4069. std::atomic
should be ill-formed - CWG Issue 3508. atomic_ref
is not well-specified - P3323 進行状況
P3325R0 A Utility for Creating Execution Environments
↓
P3325R1 A Utility for Creating Execution Environments
↓
P3325R2 A Utility for Creating Execution Environments
std::exceutionにおけるExecution Environmentsを扱うためのライブラリ機能の提案。
Execution Environments(実行環境)とはsenderチェーンによる非同期処理に依存関係を注入する方法です。例えば、アロケータやstop_token、scheduler等をカスタマイズする場合は実行環境を通してやり取りします。
実行環境はreceiverに関連付けられており、senderアルゴリズムは接続されたreceiverから実行環境を取得して利用します。実行環境そのものは単なるkey/valueストアであり、特定の取得関数をkeyとして実行環境から値を取り出します。
// receiverとしてrcvrが得られている時 auto st = get_stop_token(get_env(rcvr)); // rcvrから実行環境を取得し、stop_tokenを実行環境から取得
しかし、これまでのところ実行環境をユーザーがカスタマイズする方法はなく、これはsenderアルゴリズムの実装詳細でした。しかし、senderアルゴリズムそのものはユーザが自由に実装することができ、その場合実行環境をカスタマイズすることはその際の作業の一部になります。
また、P3284R0ではユーザーが指定した実行環境とreceiverの実行環境を統合するwrite_envというユーティリティ(senderアダプタ)が提案されていますが、これを有効活用するにはユーザーが実行環境を任意に作成できる必要があります(現在その方法はありません)。
さらに、P3149R3ではspawnとspawn_futureという新しいsenderアルゴリズムが提案されており、これらの関数にオプションの引数として実行環境を渡せるようにすることでカスタマイズ性を向上させることができます。そしてこのアプローチは、sync_waitやstart_detachedなど現在カスタマイズ性の皆無な必須部品に対しても適用でき、実行環境を引数を通して渡すことでそこで使用されるデフォルトのアロケータやstop_token等をカスタマイズすることができるようになります。
これらの理由に加えて、実行環境を引数に取るようなAPIは増えていくことが予想されているため、ユーザーが実行環境を作成するためのユーティリティが必要です。
この提案はそのようなユーティリティを追加しようとするものです。ここで提案しているのは次の3点です
execution::propというクラステンプレートを追加するpropはクエリQを値Vに関連付け、E.query(Q)がVを返すクエリ可能オブジェクトEを作成する
execution::envというクラステンプレートを追加するenvは複数の環境を1つに集約し、字句順で優先度を付ける
empty_envをenv<>に置き換え- これはオプションの提案
これらの名前は決定されたものではなく、まだ仮のものです。
1がクエリと値のペアから実行環境を作成するもので、2はそのように作成された実行環境同士を1つの実行環境に統合するものです。
namespace std::execution { // propの宣言例 template<class Query, class Value> struct prop { Query query; // exposition only Value value; // exposition only static_assert(/*...*/); constexpr const Value& query(Query) const noexcept { return value; } }; template<class Query, class Value> prop(Query, Value) -> prop<Query, unwrap_reference_t<Value>>; }
これはprop(key, value)のように構築することで実行環境を取得でき、その値eに対してe.query(key)とすることで登録したvalueを取得できます。なお、このような呼び出しは標準のクエリCPOがデフォルトで行う呼び出しでもあります。
using ex = std::execution; template<sender Sndr> ex::sender auto parameterize_work(Sndr sndr) { // ex::get_allocator(env)がmy_alloc{}を返す実行環境を作成 // ex::get_allocatorは実行環境からアロケータを取得する標準のCPO auto e = ex::prop(ex::get_allocator, my_alloc{}); // 入力`sender`(sndr)をパラメータ化してカスタムの実行環境を使用するようにする return ex::write_env(sndr, e); }
namespace std::execution { template<class Env, class Query> concept has-query = // exposition only requires (const Env& env) { env.query(Query()); }; // encの宣言例 template<queryable... Envs> struct env { Envs0 envs0; // exposition only Envs1 envs1; // exposition only ... Envsn-1 envsn-1; // exposition only template<class Query> constexpr decltype(auto) get-first() const noexcept { // exposition only constexpr bool flags[] = {has-query<Envs, Query>..., false}; constexpr size_t idx = ranges::find(flags, true) - flags; return (envsidx); } template<class Query> requires (has-query<Env, Query> ||...) constexpr decltype(auto) query(Query q) const noexcept(noexcept(get-first<Query>().query(q))) { return get-first<Query>().query(q); } }; template<class... Envs> env(Envs...) -> env<unwrap_reference_t<Envs>...>; }
これはenv(env1, env2, ...)のように使用して、渡した実行環境を統合した1つの実行環境を作成するものです。作成された実行環境eはe.query(key)のように(先程と同様に)使用して値をクエリすることができます。この時の実行環境へのクエリは内部に保存された複数のクエリに対して順番に行われますが、この順序は字句順となります。おそらくこのようなクラスはリフレクション機能を用いないと作成できないでしょう。
using ex = std::execution; template<sender Sndr> ex::sender auto parameterize_work(Sndr sndr) { // get_allocator(env) がmy_alloc{}のコピーの参照を返すような実行環境と // get_scheduler(env) がmy_sched{}のコピーの参照を返すような実行環境を統合した実行環境を作成 auto e = ex::env{ex::prop(ex::get_allocator, my_alloc{}), ex::prop(ex::get_scheduler, my_sched{})}; // 入力`sender`(sndr)をパラメータ化してカスタムの実行環境を使用するようにする return write_env(sndr, e); }
- P3284R0 finally, write_env, and unstoppable Sender Adaptors - WG21月次提案文書を眺める(2024年05月)
- P3149R0 async_scope -- Creating scopes for non-sequential concurrency - WG21月次提案文書を眺める(2024年02月)
- P3325 進行状況
P3326R0 favor ease of use
std::optional<T&>において、安全な場合に一時オブジェクトを使用できるようにする提案。
std::optional<T&>はP2988で提案されており、安全性のために右辺値からの構築が一切禁止されています。
optional<int&> dangler(optional<const int&> other, optional<int&> left, optional<int&> right) { if(random_bool()) { return left; } else { return right; } } int main() { int i = 42; optional<int&> oi1{i}; optional<int&> oi2 = dangler(oi1, oi1, oi1); // ok optional<int&> oi3 = dangler(42/* unnecessary error */, oi1, oi1); //ng }
このdangler()では、第一引数の使用(使用されていませんが)はこの関数内で完結しており、その参照はこの関数の呼び出し後に破棄されます。したがって、この場合第一引数に右辺値を渡してそれを参照したとしても実際には問題ありません。しかし、std::optional<T&>のコンストラクタの直接の文脈からそれを判定することはできないため、現在一律に禁止されています。
この提案は、このような場合にプログラマの知識をstd::optionalに伝達する方法を用意することで、このような利用を可能にしようとするものです。
この提案では、favorsという列挙型を用意して
enum class favors { safety, ease };
この列挙型の値をstd::optional<T&>に指定できるようにします
template <class T, favors favor = favors::safety> class optional<T&, favor> { ... };
なお、この変更を行うためにはstd::optional<T>でもこの2つ目のテンプレートパラメータを受け取るようにする必要があります(ただし、std::optional<T>では使用しません)。
コンストラクタではこの列挙値を使用して制限を緩和します
// 任意の参照を受け取るコンストラクタ template <class U = T> requires(!detail::is_optional<std::decay_t<U>>::value) constexpr explicit(!std::is_convertible_v<U, T>) optional(U&& u) noexcept requires (favor == favors::safety) : value_(std::addressof(u)) { static_assert( std::is_constructible_v<std::add_lvalue_reference_t<T>, U> & favor == favors::safety, "Must be able to bind U to T&"); static_assert(std::is_lvalue_reference<U>::value & favor == favors::safety, "U must be an lvalue"); } // T&を受け取るコンストラクタ constexpr optional(T& t) noexcept requires (favor == favors::ease) : value_{std::addressof(t)} {}
デフォルトはfavors::safetyであり、これは安全性を重視することを表すものです。主に
- ローカル変数
- 引数で使用してそのままリターンするもの
- コンストラクタ引数に依存するメンバ変数
- 関数引数を通じて値を返す場合の関数引数
等の場所で使用します。対して、favors::easeはより危険な場所での利用を認めるもので
voidを返す関数の入力引数- 値(not参照)を返す関数の入力引数
- その全体も一部もその関数から外に漏れることのない引数
等に使用することを意図しています。
同様の問題は他の参照セマンティクスな既存の型(std::span、std::function_ref、std::reference_wrapper)にも言えて、この提案ではこれらの型に対する変更を提案していないものの問題点について指摘しています。
式の値カテゴリの情報は必ずしもその変数の生存期間と一致しているわけではなく、デフォルトの安全性を重視するあまりにstd::optional<T&>を不必要に使い辛くするのは標準ライブラリ機能の明快さを損ねる、としています。
P3328R0 Observable Checkpoints During Contract Evaluation
P1494で提案されているUBによる影響の遡求を防止する機能を、契約アサーションに導入する提案。
契約プログラミング機能における問題点の一つとして、契約アサーション内での未定義動作の問題があります。契約アサーション内ではほぼ通常のC++と同じセマンティクスの下で契約条件式を記述できるため、そこには容易に未定義動作が混入しえます。
特に問題なのは、UBに伴って発生するタイムトラベル最適化です。契約プログラミング機能において問題になるのは次の2つのパターンです
契約アサーション内のUBによってタイムトラベル最適化が引き起こされる
int i = 0; void f(int *p) { if (p != nullptr) // #1 { ++i; } contract_assert( *p >= 0 ); // p == nullptrの場合未定義動作 }
#1の後のcontract_assertが無視ではないセマンティクスで評価される場合、その条件式は未定義動作となりコンパイラはUBが起こらないものと仮定してpは常にnullptrではないとみなすことで、#1のチェックが削除される可能性があります。この場合、f(nullptr)を渡していてenforceセマンティクスで評価されていてもiのインクリメントが観察される可能性があります。
契約アサーションの後のUBによるタイムトラベル最適化によって、契約アサーションが削除される
void g(int *p) { contract_assert( p != nullptr ); // #2 ++*p; // p == nullptrの場合未定義動作 }
#2のcontract_assertがobserveセマンティクス(チェックあり、デフォルト違反ハンドラ呼び出し、終了無し)で評価されていて、コンパイラが契約違反処理プロセスに関する知識を持っており、違反ハンドラが常に正常にリターンすることを認識している場合、後続のpでは未定義動作を起こらないものとして最適化を行うとpは常にnullptrではないため#2のチェックは自明であり削除することができます。
この場合、#2のアサーションがenforceやquick_enforceセマンティクスで評価されている場合は#2以降に継続しないためそのような最適化は不可能です。
P1494R3ではstd::observable()という特殊な関数を追加し、この関数の呼び出しが観測可能なチェックポイント(observable checkpoint)となることを規定するとともに、観測可能なチェックポイントの後続のUBがこの点を超えてプログラムをUBにしないようにすることを規定しています。
P1494は一瞬C++23に入りかけたものの、その有効性や使用法について合意を得ることができずに立ち止まっています。
この提案は、P1494で提案されている観測可能なチェックポイントという概念を利用し、契約アサーションを観測可能なチェックポイントとして規定することで前述のような契約アサーションとUBの相互作用によるタイムトラベル最適化の影響を低減することを提案するものです。ここでは次の2つの変更を提案しています
- 契約アサーション内での未定義動作によるタイムトラベル最適化の発生を防止するために、無視されないセマンティクスを持つ契約アサーションの評価の開始を観測可能なチェックポイントとする
- 契約アサーションの後の未定義動作によるタイムトラベル最適化によって契約アサーションもしくは違反ハンドラ呼び出しが削除されるのを防止するために、observeセマンティクスの評価によって呼ばれる違反ハンドラの正常なリターンを観測可能なチェックポイントとする
この2つの変更によって、前述の2パターンの契約アサーションとUBの問題を解消することができます。
この提案はSG21のレビューにおいてP2900への導入が採択されています。2つの変更点は両方とも了承されているものの、P1494の採択が条件になっています。
- 本の虫: Old New Thing: 未定義動作はタイムトラベルを引き起こす(他にもいろいろあるけど、タイムトラベルが一番ぶっ飛んでる)
- P1494R2 Partial program correctness - WG21月次提案文書を眺める(2021年11月)
- P3328 進行状況
P3330R0 User-defined Atomic Read-Modify-Write Operations
std::atomicにユーザー定義のRMW操作を行うためのAPIを追加する提案。
std::atomicのRMW(read-modify-write)操作は、算術型の特殊化に対して一部の演算についてのみ専用のメンバ関数が提供されていますが、ユーザー定義型の特殊化についてはそのようなAPIはありません。サポートされていない操作やユーザー定義型についてのRMW操作はユーザーが自前で定義する必要があります。
#include <atomic> std::atomic<float> a = 0.f; int main() { float old = a.load(), next; // float値のアトミックな指数関数RMW操作 do { next = std::expf(old); } while(a.compare_exchange_strong(old, next)); return 0; }
ユーザー定義でRMW操作を定義しようとすると、このように通常CAS(Compare-and-Swap)ループを使用して実装することになりますが、これにはいくつかの難点があります
- 進行保証(forward progress)QoIを損なうことなく実装するのが困難
- コンパイラの最適化が困難になる
- アトミック
fetch_add()を単にadd()に最適化するコンパイラは存在しない
- アトミック
- CASループはイテレーション毎にロックを複数回取得・解放するため、ロックフリーではない
std::atomicの場合パフォーマンスが低下する
これらの問題点はRMW操作そのものというよりは、その実装のために使用するCASループに伴う問題点です。この提案では、RMW操作実現のための実装の大半(CASループなど)を実装側に移動しておくことで、ユーザーが独自のRMW操作を実装する場合に上記のような問題の解消を目指すものです。
すなわち、先程の例だと
do { next = user_defined_operation(old); } while(a.compare_exchange_strong(old, next));
このuser_defined_operation()以外の部分の実装は共通であり、問題が起こりやすいのはこの部分です。user_defined_operation()はユーザーが指定するもののその他の部分について実装済みのAPIを提供することで、RMW操作はより定義しやすくなります。
この提案では、std::atomicとstd::atomic_refのユーザー定義型の特殊化に対して次の2つのメンバ関数を追加することを提案しています
template <typename T, typename UnaryOp> bool fetch_update(T& old, UnaryOp uop, memory_order order = memory_order::seq_cst) const noexcept; template <typename T, typename UnaryOp> bool fetch_update(T& old, UnaryOp uop, memory_order success = memory_order::seq_cst, memory_order failure = memory_order::seq_cst) const noexcept;
単項演算uopの結果はアトミックアクセス対象の値をアトミックに更新するために使用され、Tもしくはstd::optional<T>の値を返す必要があります。
uop(o)の値がT型の値を返す場合は、その戻り値はそのままアトミックアクセス対象の値に代入され、fetch_update()はtrueを返します。uop(o)の値がstd::optional<T>型の値を返す場合は、その.has_value() == trueの場合はTの値を返す場合と同様ですが、.has_value() == falseの場合は代入を行わずにfalseを返します。ただしどちらの場合でも、内部で読み取られてuopに渡された値はoldに書き込まれます。
このAPIを使用すると、先程の指数関数RMW操作は次のように書くことができます
#include <atomic> atomic<float> a = 0.f; int main() { float old; // float値のアトミックな指数関数RMW操作 a.fetch_update(old, [](float o) { return std::expf(o); }); return 0; }
std::pairの値の一方に応じて更新を行い、条件が満たされない場合は更新せず読み取りのみを行う例
std::atomic<std::pair<char, short>> atom; std::pair<char, short> old; bool success = atom.fetch_update(old, [](std::pair<char, short> p) -> std::optional<std::par<char, short>> { // char側の値が42より大きい場合、更新を行わない if (p.first > 42) { return std::nullopt; } else { return std::make_pair(p.first+1, p.second+2)}; } ); // oldにはpの値が読みだされている assert((success && old.first <= 42) || (!success && old.first > 42));
fetch_update()の実装戦略としては次のものをサポートすることを意図しています
- CASループベース実装
- ロックベース実装
- ロックベースCASループなど複数回ロックを取得する
- 一回だけロックを取得する
- LL/SCベース
- ハードウェアトランザクショナルメモリ
これらの実装戦略をサポートするために、UnaryOpの呼び出し演算子およびuop(o)呼び出しには次の要件が課せられます
regular_invocableであること- implicit-lifetime typeであること
noexcept(declval<UnaryOp>()(declval<T>()))がtrueであること- そのオペランドまたは非静的メンバにのみアクセスする
- 標準ライブラリのI/O関数呼び出し、同期操作、アトミック操作を実行しない
- 最終的にリターンする
この要件は、uop(o)の副作用はその非静的メンバを変更するのみであり、かつ安定(同じ入力に対して同じ出力を返す)であることを要求しています。
実装の要件は
fetch_update()の効果はuop(o)を一回だけ呼び出すuop(o)を複数回呼び出す実装はuop(o)が一回だけ呼び出されたかのように動作する場合にのみ許可される
例えば、CASループベースの実装ではuopオブジェクトをバックアップしておき、イテレーション毎にそのバックアップのコピーに対してuop(o)呼び出しを行うことでuop(o)の副作用を破棄する必要があります。
P3331R0 Accessing The First and Last Elements in Associative Containers
※この部分は@Sakky4869さんに執筆して頂きました!
連想コンテナに対して、2つの関数front()、back()を追加する提案です。
StackOverflowでは以下の2つの質問が多く見受けられます。
- mapコンテナで最初の要素を取得する方法
- std::mapの最後の要素のkeyを取得する方法
このような課題に対して、最初の要素を取得する場合は、以下のような方法を提案しています。
| 現在 | 提案 |
|---|---|
*m.begin() |
m.front() |
(*m.begin())->first |
m.front().first |
(*m.begin())->second |
m.front().second |
また、最後の要素を取得する場合は以下のような方法を提案しています。
| 現在 | 提案 |
|---|---|
*m.rbegin() *prev(m.end()) *--m.end() |
m.back() |
(*m.rbegin())->first *prev(m.end())->first (*--m.end())->first |
m.back().first |
(*m.rbegin())->second *prev(m.end())->second (*--m.end())->second |
m.back().second |
類似した提案について、C++20で追加された連想コンテナのcontains()が挙げられています。
関数の命名は、front() / back()の他に、first() / last(), min() / max()が提案されていました。
P3332R0 A simpler notation for PM
P2688R1のパターンマッチング提案に対して、名前を導入するパターン構文の改善提案。
P2688に関しては以前の記事を参照
P2688では、パターンにマッチしたものに名前を付けて参照するのにletを使用します。
std::tuple<double double> p = ...; p match { [0, 0] => std::print("on origin"); [0, let y] => std::print("on y-axis at {}", y); [let x, 0] => std::print("on x-axis at {}", x); let [x, y] => std::print("at {}, {}", x, y); };
この提案ではこの構文が煩雑であるとして、代わりの構文を提案しています。
ここで提案されているのは、単にletを無くしてpattern name => actionの形で記述するようにした構文です。先程の例を書き直すと次のようになります
p match {
[0, 0] => std::print("on origin");
[0, _ y] => std::print("on y-axis at {}", y);
[_ x, 0] => std::print("on x-axis at {}", x);
_ [x, y] => std::print("at {}, {}", x, y);
};
最後のパターンのように、_を任意のものにマッチする構文として一貫的に使用しながらマッチしたものに名前を付けられるようになります。
letによる名前導入の例
let x // x is new [a, let y] // a is old, y is new [let x, b] // x is new, b is old let [x, y] // x and y are both new let [x, [y, z]] // x, y, z are all new
この提案による例
_ x // x is new [a, _ y] // a is old, y is new [_ x, b] // x is new, b is old _ [x, y] // x and y are both new _ [x, [y, z]] // x, y, z are all new
ただし、最後の例に関してはネストした場合の特別ルールとして[_ x, _[y, z]]と書けるようにすることを提案しています。
std::variantの例
| P2688R1 | この提案 |
|---|---|
std::variant<int, bool, std::string> parse(std::string_view); parse(some_input) match { int: let i => // ... bool: let b => // ... std::string: let s => // ... }; |
parse(some_input) match { int i => // ... bool b => // ... std::string s => // ... }; |
ポインタの例
| P2688R1 | この提案 |
|---|---|
void f(int* p) { p match { ? let i => // ... nullptr => // ... }; } |
void f(int* p) { p match { ? _ i => // ... nullptr => // ... }; } |
提案文書にはもう少し対応例があります。
この提案では純粋に構文の変更のみを提案しており、意味論の変更は提案していないため、変更後のコードは変更前のものと同じ意味を持ちます。また、現在パターンマッチング提案としてはもう一つP2392がありますが、この提案はどちらの提案を推すものでもありません。
P3335R0 Structured Core Options
コンパイラフロントエンドの共通コマンドラインオプション構文の提案。
ビルドシステムをはじめとするC++ツールはC++コンパイラフロントエンドを呼び出すために異なるオプションをコンパイラに合わせて使い分ける必要があります。現在のところそれは実装できていますが、この先増大する複雑さを低減するためには、コンパイラ間で共通して使用可能なオプション言語ともいえるものが必要です。
この提案は、そのために構造化されたオプションの共通セットを提案するものです。この提案によって、例えば次のようなことが可能になります
- コンパイラフロントエンドとやり取りするツールによる実装の再利用
- 消費者or提供者として、共通オプションを利用するツールの採用拡大
- 初学者にとって学ぶべきことが減ることで、参入障壁が低くなる
例えば、Hello worldのプログラムをコンパイルするコマンドはgccとMSVCで次のようになります
"g++" -O0 -fno-inline -Wall -g -static "hello.cpp" -o "hello"
"cl" "hello.cpp" /Fehello -TP /EHs /GR /Z7 /Od /Ob0 /W3 /Op /MLd /DEBUG /subsystem:console
これをこの提案の共通オプションを用いて記述すると次のようになります
{ "source": "hello.cpp", "output": { "hello": "exec" }, "optimization": { "compile": "off", "inline": false }, "warnings": { "enable": "all" }, "debug": true, "runtime": { "multithread": false, "debug": true, "static": true }, "vendor": { "msvc": { "subsystem": "console" } } }
これはコマンドラインで直接記述して渡すようなものではなく、ファイルに格納して渡すものです。そのファイル形式やオプションについてはP3051で提案されています。ここで提案しているのは、各C++コンパイラがほぼ同じ意味論で用意していて良く使用されているオプションについて、P3051のファイル形式で記述可能なように共通化したオプション指定方法についてです。
ソースコードのように複数の値を指定するオプションでは、JSONの配列が使用できます
{ "source": [ "bindjam.cpp", "builtins.cpp", ... ], ... }
-Dによって指定される事前定義マクロを指定する例
{ "define": { "BOOST_ALL_NO_LIB": 1, "_WIN32_WINNT": "0x0600", "_GNU_SOURCE": true, "U_USING_ICU_NAMESPACE": false, "NOMINMAX": null } }
最適化オプションの例
{ "optimization": "minimal" }
{ "optimization": "speed" }
提案では
- ソースファイルの指定
- 出力名とその種類の指定
- インクルードディレクトリの指定
- リンクするライブラリの指定
- マクロ定義の指定
- マクロundefの指定
- 言語の指定
- 最適化・デバッグの指定
- ベンダ固有オプションの指定
について、既存コンパイラ(MSVC、GCC)とツール(CMake、B2)におけるオプション構文を比較するとともに、提案する共通オプションの構文とセマンティクスを詳細に検討しています。
P3336R0 Usage Experience for Contracts with BDE
Bloomberg社内において使用されていた契約チェック機能をP2900で置き換えた実験の報告書。
この文書で報告されている実験の目的は、P2900の契約プログラミング機能の従来のアサーションと異なる点である暗黙const化と評価回数の規定なし(複数回評価されうる)の影響について調べることです。
実験は、Bloomberg社内のBDEライブラリというライブラリで使用されているbsls_assertというアサーションをcontract_assertを使うように書き換えて行われています。また、BDEのほかに規模は少し小さくなるものの4つの内部ライブラリでテストしています。
実験の一つ目は、暗黙const化の影響について調べることです。これは、GCCの実験ブランチで実装中のP2900R7ベースの契約プログラミング機能の実装を利用して対象のライブラリをコンパイルすることで行われました。
テスト対象のコードベースは次のようなものです
| ライブラリ | コンポーネント | 行数 | テスト行数 | アサーション | テストアサーション | 問題点 |
|---|---|---|---|---|---|---|
| BDE | 3330 | 1.32M (70.52%) | 2.14M (76.02%) | 7749 (0.83%) | 4743 (0.29%) | 7 |
| Library #1 | 1814 | 368.30K (62.71%) | 986.45K (79.18%) | 6307 (2.73%) | 981 (0.13%) | 4 |
| Library #2 | 165 | 45.49K (74.68%) | 64.77K (75.86%) | 231 (0.68%) | 240 (0.49%) | 0 |
| Library #3 | 1084 | 352.58K (79.90%) | 116.20K (88.73%) | 1844 (0.65%) | 138 (0.13%) | 2 |
| Library #4 | 240 | 86.61K (60.09%) | 17.79K (85.48%) | 1156 (2.22%) | 5 (0.03%) | 1 |
各列の意味:
- コンポーネント: .hと.cppのペアの数、および関連するテストドライバ
- 行数とテスト行数: コードの行数。空行やコメントを除いた行数の割合をパーセントで示し、ライブラリのサイズのおおよその尺度としています。本番コード (.hと.cppファイル) とテストドライバコードに分かれています
- アサーションとテストアサーション:
bsls_assertマクロの使用回数。空行やコメントを除いたコード行数に対するアサーションの割合をパーセントで示し、これも本番コードとテストドライバコードに分かれています。この割合は、個々のライブラリでアサーションがどれだけ一貫して使用されているかを示しています - 問題点:
bsls_assertの実装でcontract_assertを使用するように切り替えたために対処する必要があった、異なる問題の数
そして、1つ目の実験の結果は次のようになりました
| ライブラリ | constサポートの不足 |
変更しない使用 | 意図的な失敗 | 破壊的な述語 | バグ | 合計 |
|---|---|---|---|---|---|---|
| BDE | 1 | 4 | 1 | 1 | 0 | 7 |
| Library #1 | 3 | 1 | 0 | 0 | 0 | 4 |
| Library #2 | 0 | 0 | 0 | 0 | 0 | 0 |
| Library #3 | 1 | 0 | 0 | 0 | 6 | 7 |
| Library #4 | 0 | 0 | 0 | 0 | 1 | 1 |
各列の意味:
constサポートの不足:const修飾が正しく行われていなかっAPIの使用による問題- 値を変更しない非
constでの使用: 値を変更しないが、非constの変数を使用する必要があることによる問題 - 意図的な失敗: テストのために意図的に失敗するように設計されたアサーションによる問題
- 破壊的な述語: 同じセマンティクスで一貫して評価されない場合、正しい結果を生成しなくなる述語による問題
- バグ: 代入演算子(
=)を等価比較演算子(==)の代わりに誤って使用することによる問題。
全体として、bsls_assertからcontract_assertへ以降するための労力はほぼ皆無だったと、としています。
2つ目は、契約述語が繰り返し評価される場合の影響を見る実験で、これはアサーションの述語を64回繰り返して評価するようにして、BDEライブラリを普段ビルドしている製品版のコンパイラでビルドすることで行われました。
実験の結果、次のことが明らかになりました
- 実行時の動作品質を向上させ、一度報告された違反が再度報告されないようにするために、違反が検出された場合(たとえそれがobserveセマンティクスであっても)、繰り返し評価を停止する、ことにした
- この決定は、テストや既存のコードには影響を与えないもののこの機能を提供するコンパイラでは考慮すべき点
- 2つのテストドライバは、テスト対象のコードによって実行された操作をカウントしていた
- ファズテストユーティリティのテストの一環として意図的に失敗するように設計されたアサーションは、最初の繰り返しで依然として失敗し、繰り返し評価戦略では問題として検出されなかった
- ローカルカウンタを変更していたアサーションは、繰り返し評価によって見事に失敗したため、修正される予定
とはいえ、これらの問題を解決するための量力はBDEライブラリ全体を数回ビルドする時間に比べると僅かなものだったとのことです。
文書では、これらの実験から次のような教訓を得られたとしています
- アサーションの大部分は変更を必要とせずに正しく機能する
- テストしたライブラリでは
const化によってオーバーロード解決結果が変更されてバグるアサーションは一つもなかった - この実験だけでも、見つかっていなかったバグや疑わしい設計がいくつか発見されたことで、ライブラリの品質が向上した
総合的に見ると、P2900の契約プログラミング機能で争点となっている上記2つの問題点の実際の影響は皆無ではないものの軽微であり、それによる恩恵が上回る、という方向性の報告です。
P3338R0 Observe and ignore semantics in constant evaluation
定数式における契約チェックのセマンティクスとして、observe/ignoreが有効であることを説明する文書。
ここでの主張は、防衛的なチェックと契約チェックを併用している場合に、定数式における契約チェック時にもobserve/ignoreセマンティクスによる評価が有用となる、ということです。
例えば次のようなコードにおいて
int f(int x) pre(x >= 0) { // 防衛的なチェック(事前条件と一部重複する if (x < 0) { return -1; } // 関数の主処理 return x * 2; }
この関数は事前条件を持つものの、防衛的なチェックを行っていることで事前条件に違反した呼び出しを行っても安全です。このようなコードは既存のコードからの移行によって書かれる可能性があり、この関数を既に使用している呼び出し下では負の数で呼び出している場合があるかもしれませんが安全に動作します。
契約チェックの有効化後にそのようなバグを発見するには、このpre()をobserveセマンティクスで評価することで行えます。誤った呼び出し元は契約違反となるものの、診断が発行されるとともに引き続き安全に動作します。
このような関数をconstexpr化した後でも、(コンパイル時の契約注釈のセマンティクスとしてobserveが使用できれば)コンパイル時の評価においても同様の事が保証されます。また、その場合にignoreセマンティクスを選択すれば警告すら表示されません。防衛的なチェックによって契約違反は必ずしも致命的ではないので、このような選択が可能になります。
このようなアプローチを効果的に使用するには契約注釈に個別にセマンティクスを指定するラベルのようなものが必要になりますが、そのようなラベルが無くても使用することができるため、コンパイル時の契約チェックのセマンティクスとしてobserve/ignoreには有用性があります。
現時点のP2900R7でもコンパイル時の契約注釈のセマンティクスとしては実行時と同様に4種類が有効であり、この文書はどうやらその設計根拠に追加の動機付けを与えるもののようです。
P3339R0 C++ Ecosystem IS Open License
Ecosystem ISをCC-BYライセンスの下で公開する提案。
Ecosystem ISはC++周辺ツールとエコシステムの相互運用性を高めるための共通の基盤を整備するための国際標準規格であり、2025年中の発行を目指して目下作業中です。
C++の周辺ツールとエコシステムは既に多くのものが存在し、日々進化を続けており、そのようなツールやシステムの多くは様々な国や企業の開発者のコミュニティによって開発されています。
Ecosystem ISが効果的であるためには、過剰なオーバーヘッドなしに、コミュニティのアイデアや経験をタイムリーに取り入れることができなければなりません。特に、コミュニティはEcosystem ISに貢献し、その後、できるだけ円滑に自分たちのエコシステムでEcosystem ISを実装できるようにする必要があります。
それを円滑に行うための方法の一つとしてここでは、オープンなライセンスによってEcosystem IS関連の文書を公開しておくことを提案しています。これによって、エコシステムのコミュニティはEcosystem IS関連の文書を自由に共有及び参照することができ、実装やフィードバックのスピードアップを図ることができます。
ここでの提案は次の3点です
- Ecosystem ISに関連するPnnnn番号の文書(個別の提案)の著作権は著者に帰属し、"Creative Commons Attribution 4.0 International License" (CC-BY-4.0)の下でライセンスされる
- 作業の結果得られたEcosystem ISのNnnnnドラフト文書と公開された国際標準規格の著作権は全ての著者とISO/IECに帰属する
- 作業の結果得られたEcosystem ISのNnnnnドラフト文書と公開された国際標準規格は、CC-BY-4.0の下でライセンスされ、必要な帰属表示が含まれる
提案では、ISOの著作権ポリシーに適合しており、正当化されることを説明しています。
P3340R0 A Consistent Grammar for Sequences
C++の文法規則におけるシーケンスの定義を統一する提案。
C++の文法上のシーケンスとは例えば、指定された特定の文字の並びとして何らかの文字列による文法要素(ある種の文字列など)を定義しているものです。その例としては2桁以上の数値や2文字以上の文字列などがあります。これ以外にもC++文法上のシーケンスにはいくつかの種類があります。
2終端シーケンス
これはシーケンスの最も一般的な形式で、単一要素によって終端を指定したもの(長さ1のシーケンス)と、要素が再帰的に続いたうえで単一要素が終端としておかれることによってシーケンスをなすもの、によって構成されるシーケンスです。
例えば次のように定義されます
c-char-sequence : c-char c-char-sequence c-char
c-char-sequenceは文字リテラルの内部の構文を定義するものです。
同様のシーケンス定義は次の構文要素で使用されています
c-char-sequenced-char-sequenceh-char-sequencen-char-sequenceq-char-sequencer-char-sequences-char-sequencesimple-octal-digit-sequencesimple-hexadecimal-digit-sequencebalanced-token-seqdeclaration-seqlabel-seqlambda-specifier-seqrequirement-seqstatement-seqvirt-specifier-seqelif-groupspp-tokensh-pp-tokens
末尾シーケンスがオプションなもの
これは、先頭の単一要素を終端として、その後ろにオプションで再帰的に自身を置いたものです。例えば次のように定義されます
cv-qualifier-seq : cv-qualifier cv-qualifier-seq(opt)
末尾の(opt)は省略可能であることを表します。cv-qualifier-seqはCV修飾指定の文法定義です。
同様のシーケンス定義は次の構文要素で使用されています
cv-qualifier-seqhandler-seqconversion-declaratormember-specification
先頭シーケンスがオプションなもの
これは、先程とは逆に省略可能なリストを先頭に置いたものです。例えば次のように定義されます
attribute-specifier-seq : attribute-specifier-seq(opt) attribute-specifier
attribute-specifier-seqは属性リストの文法定義です。この定義はこれでしか使用されていません。
偽装リスト
これは、オプションの区切り文字の挿入を許可しているタイプのシーケンスです
hexadecimal-digit-sequence : hexadecimal-digit hexadecimal-digit-sequence '(opt) hexadecimal-digit
hexadecimal-digit-sequenceは0xのプリフィックスの後に続く16進数値列の構文定義です。'を区切り文字として使用できるものの区切り文字で開始できないためこのようなシーケンス定義となっています。これは厳密にはシーケンスではなく、リストになっています。
同様の定義は次の構文要素で使用されています
digit-sequencehexadecimal-digit-sequence
これらの種類のシーケンスでは元のリスト形式の定義を維持する必要があります。
シーケンスのグループ
これは、他のシーケンスのグループとなっているシーケンスです。これそのものはシーケンスではないためこの提案の対象ではありません。例えば次のように定義されます
escape-sequence : simple-escape-sequence numeric-escape-sequence conditional-escape-sequence
同様のシーケンス定義は次の構文要素で使用されています
decl-specifier-seqdefining-type-specifier-seqescape-sequencenumeric-escape-sequencetype-specifier-seq
エスケープシーケンス
これは命名として-sequenceとなっているものの、ここまでのものと異なり要素の繰り返しによるシーケンスではないものです。例えば次のように定義されます
simple-escape-sequence : \ simple-escape-sequence-char
これに該当するものは全てエスケープシーケンスです
conditional-escape-sequenceoctal-escape-sequencesimple-escape-sequence
これもこの提案の対象ではありません。
この提案は、最後の2つを除いてシーケンスの定義を共通化しようとするものです。
ただし、ここでは名前の一貫性(-seqだったり-sequenceだったり、どちらでもなかったり)を修正することは提案していません。名前を変更すると、その文法要素が参照されているところも変更する必要があり、変更範囲が大きくなるためです。
提案では、末尾シーケンスがオプションなものの文法定義をシーケンスを定義する際の共通定義として採用することを提案しています。
xxx-seq : xxx xxx-seq(opt)
2終端ではなく1終端を採用することで、偽装リスト形式と明確に区別できるようになります。
この提案ではさらに、文法要素としてのシーケンスを定義する場合のCWGのポリシーについても提案しています。提案しているポリシーは次の2つです
- シーケンス定義のポリシー
- シーケンス命名のポリシー
この提案は2024年11月の全体会議で承認され、ドラフトに適用されています。
P3341R0 C++ Standard Library Ready Issues to be moved in St Louis, Jun. 2024
6月に行われたSt Louis会議でWDに適用されたライブラリに対するIssue報告の一覧
- 3944. Formatters converting sequences of
charto sequences ofwchar_t - 4060.
submdspanpreconditions do not forbid creating invalid pointer - 4061. Should
std::basic_format_contextbe default-constructible/copyable/movable? - 4071.
reference_wrappercomparisons are not SFINAE-friendly - 4074. compatible-joinable-ranges is underconstrained
- 4076.
concat_viewshould be freestanding - 4079. Missing Preconditions in
concat_view::iterator's conversion constructor - 4082.
views::concat(r)is well-formed whenris anoutput_range - 4083.
views::as_rvalueshould reject non-input ranges - 4096.
views::iota(views::iota(0))should be rejected - 4098.
views::adjacent<0>should reject non-forward ranges - 4105.
ranges::ends_with's Returns misses difference casting - 4106.
basic_format_argsshould not be default-constructible
P3342R0 Working Draft, Standard for C++ Ecosystem
Ecosystem ISのワーキングドラフト。
これはP2656て作業予定が提案されていた、C++周辺ツールのための共通の枠組みを定義する国際標準規格の最初のドラフトです。
ここではP2717(ツールのEcosystem ISへの準拠度のクエリ)とP3335(コンパイラフロントエンドのオプションの共通構文)の2つの提案の内容が採択されているようです。
P2656で示されていたスケジュールによればこの文書の作成完了は2024年3月予定だったので、少し遅れているかもしれません。次の予定は、2025年2月のCommittee Draft (CD)作成完了です。
- P2656R1 C++ Ecosystem International Standard - WG21月次提案文書を眺める(2023年01月)
- P2717R5 Tool Introspection - WG21月次提案文書を眺める(2023年12月)
- P3342 進行状況
P3343R0 Contracts - What are we doing here (EWG Presentation)
P2900の契約プログラミング機能についてEWGのメンバに説明するスライド資料。
特に、P2900が行ってきた重要な設計上の決定事項について説明することを目的としているようです。
P3344R0 Virtual Functions on Contracts (EWG - Presentation for P3097)
P2900の契約プログラミング機能に関して、仮想関数に対する契約に関してEWGのメンバに説明するスライド資料。
P2900の現在の仕様では仮想関数には契約を行えません。それは恒久的なものではなく一時的なものですが、その緩和アプローチとして呼出し元(静的型)と呼び出し先(動的型)の両方で契約チェックを行うことで許可しようとする提案がいくつかあります。
このスライドはそのような提案の一つであるP3097のアプローチを解説するものです。
P3345R0 Core Language Working Group "ready" Issues for the June, 2024 meeting
6月に行われたSt Louis会議でWDに適用されたコア言語に対するIssue報告の一覧。
- 233. References vs pointers in UDC overload resolution
- 2144. Function/variable declaration ambiguity
- 2561. Conversion to function pointer for lambda with explicit object parameter
- 2588. friend declarations and module linkage
- 2728. Evaluation of conversions in a delete-expression
- 2818. Use of predefined reserved identifiers
- 2819. Cast from null pointer value in a constant expression
- 2836. Conversion rank of
long doubleand extended floating-point types - 2858. Declarative nested-name-specifiers and pack-index-specifiers
- 2858. Declarative nested-name-specifiers and pack-index-specifiers
- 2859. Value-initialization with multiple default constructors
- 2861.
dynamic_caston bad pointer value - 2864. Narrowing floating-point conversions
- 2865. Regression on result of conditional operator
- 2867. Order of initialization for structured bindings
- 2869.
thisin local classes - 2870. Combining absent encoding-prefixes
- 2871. User-declared constructor templates inhibiting default constructors
- 2872. Linkage and unclear "can be referred to"
- 2874. Qualified declarations of partial specializations
- 2876. Disambiguation of
T x = delete("text") - 2877. Type-only lookup for using-enum-declarator
- 2881. Type restrictions for the explicit object parameter of a lambda
- 2882. Unclear treatment of conversion to
void - 2883. Definition of "odr-usable" ignores lambda scopes
- 2886. Temporaries and trivial potentially-throwing special member functions
- 2887. Missing compatibility entries for xvalues
- 2891. Normative status of implementation limits
- 2892. Unclear usual arithmetic conversions
- 2895. Initialization should ignore the destination type's cv-qualification
P3351R0 views::scan
状態を持つ関数を使用可能なviews::transformであるRangeアダプタ、views::scanの提案。
rng | views::transfrom(f)はrngの各要素にfを適用した結果からなる範囲を生成するRangeアダプタですが、このfはstd::regular_invocableであることが要求されており、このため状態を持つ(かつそれを更新するような)関数の使用はコンセプトの意味論要件違反となり未定義動作となります。
しかし、状態を持つ関数によってviews::transfromしたい場合というのはそれほど珍しいことではありません。例えば、std::inclusive_scan(範囲の部分和を計算し別の範囲に出力するアルゴリズム)のようなことを遅延評価で行いたい場合などが考えられます(これにはviews::transfromを使用できません)。
この提案ではそのために、新しいRangeアダプタであるviews::scanを提案しています。
ここで提案されているviews::scanは状態を持つ関数を使用可能なviews::transformとは少し異なり、regular_invocableな関数を受け取り、内部で状態の初期値として入力範囲の最初の要素を取得して、残りの各要素に対して状態と要素を関数に渡した結果を要素とする範囲を生成します(この時、関数の適用結果で状態を更新します)。
これは遅延評価かつ汎用的なstd::inclusive_scanであり、遅延評価するstd::inclusive_scan相当のものとして(適用する関数をstd::plusに固定したもの)views::partial_sumを、初期値を別に指定するviews::scanとしてviews::prescanを追加で提案しています。
namespace std::ranges { // views::scanアダプタの実装view型 template<input_range V, typename T, move_constructible F> requires view<V> && is_object_v<T> && is_object_v<F> && regular_invocable<F&, T&, range_reference_t<V>> && assignable_from<remove_cvref_t<invoke_result_t<F&, T&, range_reference_t<V>>>&, T&> && can-reference<invoke_result_t<F&, T&, range_reference_t<V>>> class scan_view; // freestanding namespace views { // views::scanアダプタのファミリー inline constexpr unspecified scan = unspecified; // freestanding inline constexpr unspecified prescan = unspecified; // freestanding inline constexpr unspecified partial_sum = unspecified; // freestanding } }
サンプルコード
import std; int main() { std::vector vec = {1, 2, 3, 4, 5}; auto scan = vec | std::views::scan(std::plus{}); auto prescan = vec | std::views::prescan(10, std::plus{}); auto partial_sum = vec | std::views::partial_sum; std::println("scan: {}", scan); std::println("prescan: {}", prescan); std::println("partial_sum: {}", partial_sum); }
この出力は次のようになります
scan: [1, 3, 6, 10, 15] prescan: [10, 11, 13, 16, 20, 25] partial_sum: [1, 3, 6, 10, 15]
この3つのRangeアダプタは全て、基底の実装としてscan_viewを共有しています。
その他の特性は次のようになります
referenceinvoke_result_t<F&, T&, ranges::range_reference_t<V>>
rangeカテゴリVがforward_rangeの場合:forward_range- それ以外の場合:
input_range
common_range: ×sized_range:Vがsized_rangeの場合const-iterable:Vがconst-iterableかつ、const Fが呼び出し可能である場合borrowed_range: ×
value_typeはreferenceをremove_cvrefした型になります。なお、referenceの型の決定はranges::foldと同じになっています。
また、borrowed_rangeに関しては現時点では常に満たさないものの、P3117が採択される場合に条件付きで可能になります(ここでは提案していません)。
P3354R0 Slides for P3233R0
P3233R0の説明スライド。
P3233R0の内容(P2786のトリビアルリロケーション機能に関する問題点の報告)についての内容を説明したスライドです。2024年6月のSt. Louis会議でWG21メンバに向けてプレゼンされたもののようです。
P3355R0 Fix submdspan for C++26
C++26std::submdspanへの修正提案。
この提案では次の2つの修正を提案しています
- ユーザー定義型をスライス指定で使用できるようにする
- 行優先/列優先(及び
~_paddedな)レイアウトに対して、スライスにコンパイル時定数が使用されていて条件を満たす場合に元のレイアウト情報を保持するようにする- コンパイル時定数エクステントの指定に対して、隣接性を維持する
ユーザー定義型をスライス指定で使用できるようにする
std::submdspanではmdspanの参照しているレイアウトによる配列から、さらに部分行列をインデックス範囲指定によって取得することができます。それは、std::submdspanのスライス引数に対してstd::pairやstd::tupleによって半開区間を指定することで行えます。
int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // 3行4列の行列を参照するmdspan std::mdspan<int, std::extents<std::size_t, 3, 4>> mat_43{arr}; // |1 2 3 4| // |5 6 7 8| // |9 10 11 12| // 上記行列の1行目から2行と0列目から3列の範囲を参照する部分行列を取得 auto mat_23 = std::submdspan(mat_43, std::pair{1, 3}, std::pair{0, 3}); // |5 6 7| // |9 10 11| }
このような指定を行う場合に使用できるのはindex-pair-likeという説明専用のコンセプトを満たす型ですが、pair-likeという説明専用コンセプトを含んでいることでget<0>とget<1>が使用できることを要求しており、これによって整数のペアを表現するためにはstd::pairのようなtuple-likeな型を使用する必要があります。
この問題点は、例えばintegral_constant2つをメンバに持つ構造体によってインデックス範囲指定が行えない(get<0>とget<1>は参照を返す必要があるため)ことです。
// 整数ペアを表す空のクラス template<std::integral auto Begin, std::integral auto End> struct index_pair { [[no_unique_address]] std::integral_constant<std::size_t, Begin> a; [[no_unique_address]] std::integral_constant<std::size_t, End> b; }; int main() { int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; // 3行4列の行列を参照するmdspan std::mdspan<int, std::extents<std::size_t, 3, 4>> mat_43{arr}; // 上記行列の1行目から2行と0列目から3列の範囲を参照する部分行列を取得(したい auto mat_23 = std::submdspan(mat_43, index_pair<1, 3>{}, index_pair<0, 3>{}); // ng }
このindex_pairのような構造体のサイズは最小であるため、submdspanから返されるmdspanのサイズオーバーヘッドを削減することができます。しかしこのような型はstd::get<0>等を実装できないため、現在のsubmdspanではサポートできません。
この提案では、現在の要求にあるpair-likeコンセプトを、構造化束縛が機能すること(かつtuple_sizeが2であること)、という要件に置き換えることでこれをサポートできるようにすることを提案しています。
コンパイル時定数エクステントの指定に対して、隣接性を維持する
std::mdspanとstd::aligned_accessorを使用して1次元配列のコピー操作をベクトル化しようとするコードを書こうとする場合(コード例は提案参照)、にコンパイル時エクステントを持つスライス(std::submdspan)を使用すると、現在の規定では2つの問題が発生します
submdspanを取った後でも連続していることが分かっている場合でも、layout_strideが使用されるis_always_exhaustive() == falseとなってしまう- 例えば代わりに
layout_rightなどの連続性が保証されるレイアウトを使用してほしい
aligned_accessorもdefault_accessorに変換されてしまうaligned_accessor::offset()がstd::size_tを引数に取るため- オフセット係数が何らかのオーバーアライメント係数で割り切れるかどうかなどコンパイル時の情報が破棄される
この提案では、入力mdspanのレイアウトポリシーがlayout_left, layout_right, layout_left_padded, layout_right_paddedである場合の1の問題を修正することを提案しています。
2の問題は破壊的変更なしでこれを行えないため、解決を提案してはいません。
P3356R0 non_invalidating_vector
要素およびその参照が無効化されない保証のあるstd::vectorのラッパを提供する提案。
std::vectorでは、要素を追加していくと必ずどこかで内部キャパシティを超えてメモリの再確保と要素の再配置が起こり、それ以前に取得された要素への参照やイテレータが無効化されます。std::vectorの特性上これはどうしようもないものではありますが、時としてこの動作は危険なものとなります。回避するにはstd::listをはじめとする要素安定性の保証があるコンテナを使用する必要がありますが、そのようなコンテナはstd::vectorのように要素の連続性(隣接性)がなく、パフォーマンスで劣ります。
この提案では、std::vectorをラップする形で要素無効化が起こらないことを保証する型を導入することでこの問題に対処しようとしています。
次の2つのものを提案しています
non_invalidating_vector:std::vectorの参照ラッパnon_invalidating_vector_ref:std::vectorを使用するコンテナアダプタ
どちらの型でも、std::vectorをラップしてメンバ関数は要素を無効化しないもののみを提供することで要素無効化が起こらないようにしています。
non_invalidating_vectorは内部でstd::vectorを保持しており、non_invalidating_vector_refはstd::vectorへの参照を保持します。non_invalidating_vector_refはより厳密なconst std::vector<T>&であり、関数引数でstd::vectorを受け取る際に使用することを意図しています。
使用感の例
void non_invalidating(non_invalidating_vector_ref<int> niv, const std::vector<int>& cv) { // nivの要素が無効となる心配はない // cvの要素が無効になる心配はない ... } int main() { std::vector<int> vs; non_invalidating_vector<int> niv; // 要素無効化の心配から解放される non_invalidating(vs, vs); non_invalidating(niv, vs); [](non_invalidating_vector_ref<int> vs) { // 要素が無効化される心配がない }(vs); for (auto &s : vs) { [](non_invalidating_vector_ref<int> vs) { // 要素が無効化される心配がない }(vs); } }
定義の例
// non_invalidating_vectorの定義例 template< class T, class Allocator = std::allocator<T>, class Container = std::vector<T, Allocator> > class non_invalidating_vector { private: actual_type inner; public: // has all of the std::vector constructors constexpr non_invalidating_vector() noexcept(noexcept(Allocator())) : inner() {} constexpr explicit non_invalidating_vector( const Allocator& alloc ) noexcept : inner(alloc) {} constexpr non_invalidating_vector( size_type count, const T& value, const Allocator& alloc = Allocator() ) : inner(count, value, alloc) {} explicit non_invalidating_vector( size_type count, const Allocator& alloc = Allocator() ) : inner(count, alloc) {} template< class InputIt > constexpr non_invalidating_vector( InputIt first, InputIt last, const Allocator& alloc = Allocator() ) : inner(first, last, alloc) {} constexpr non_invalidating_vector( const non_invalidating_vector& other ) : inner(other) {} constexpr non_invalidating_vector( const non_invalidating_vector& other, const Allocator& alloc ) : inner(other, alloc) {} constexpr non_invalidating_vector( non_invalidating_vector&& other ) noexcept : inner(other) {} constexpr non_invalidating_vector( non_invalidating_vector&& other, const Allocator& alloc ) : inner(other, alloc) {} constexpr non_invalidating_vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() ) : inner(init, alloc) {} template< class R > constexpr non_invalidating_vector( std::from_range_t, R&& rg, const Allocator& alloc = Allocator() ) : inner(std::from_range, rg, alloc) {} // all non invalidating methods are proxied constexpr reference operator[]( size_type pos ) { return inner[pos]; } constexpr const_reference operator[]( size_type pos ) const { return inner[pos]; } constexpr size_type size() const { return inner.size(); } // all invalidating methods are deleted constexpr void resize( size_type count ) = delete; // compatible with non_invalidating_vector_ref operator non_invalidating_vector_ref<T, Allocator>() { return non_invalidating_vector_ref<T, Allocator>{inner}; } // can narrow scope to just the const members operator const actual_type&() const { return inner; } };
// non_invalidating_vector_refの定義例 template< class T, class Allocator = std::allocator<T> > class non_invalidating_vector_ref { private: actual_type& ref; public: // constructors reflect this being just a pure reference type constexpr non_invalidating_vector_ref() = delete; constexpr non_invalidating_vector_ref(const non_invalidating_vector_ref&) = default; constexpr non_invalidating_vector_ref(non_invalidating_vector_ref&&) = default; constexpr non_invalidating_vector_ref operator=(const non_invalidating_vector_ref&) = delete; constexpr non_invalidating_vector_ref operator=(const non_invalidating_vector_ref&&) = delete; constexpr non_invalidating_vector_ref(actual_type& reference) : ref{reference} {} // all non invalidating methods are proxied constexpr reference operator[]( size_type pos ) { return ref[pos]; } constexpr const_reference operator[]( size_type pos ) const { return ref[pos]; } constexpr size_type size() const { return ref.size(); } // all invalidating methods are deleted constexpr void resize( size_type count ) = delete; // can narrow scope to just the const members operator const actual_type&() const { return ref; } };
この提案は、P3274で開始された安全性プロファイルにおいて必要性が提示されたことを受けて書かれたものの様です。
P3357R0 NRVO with factory and after_factory
コピーもムーブもできないようなクラスの値を作成するためのファクトリ関数の作成を容易にするための機能の提案。
コピーもムーブもできないようなクラスの値をコード内の任意の場所で展開するために、ファクトリ関数が利用されます。RVOを活用して、関数内で初期化処理を済ませたうえで戻り値で返すことでそのようなクラスの値の可搬性を向上させることができます。
しかしその場合、関数のreturn文で直接的に対象の型の値を構築できれば(return文にprvalueを渡せれば)RVOが保証されるのですが、そうでない場合に行われるNRVOは必須ではないため必ずしも行われません。
struct non_move_and_copy { non_move_and_copy() { ... } // コピー+ムーブ不可 non_move_and_copy(const non_move_and_copy&) = delete; non_move_and_copy& operator=(const non_move_and_copy&) = delete; // 初期化処理を行うなどの追加作業 void init() { ... } }; auto factory() -> non_move_and_copy { non_move_and_copy a{}; // aを構築した後で何か追加の作業を行う必要がある a.init(); // コピー/ムーブどちらかのコンストラクタは利用可能である必要がある return a; // ❌コンパイルエラー }
このような用途に対応するために、NRVOが可能な場合は必須に仕様とする提案はP2025R2として提出されているもののうまく進んでおらず、C++26には間に合いそうにありません。筆者の方はこれはC++29にも間に合わないと考えており、この提案はそれが導入されるまでの間利用可能な過渡的なソリューションを導入しようとするものです。
ここで提案しているのはstd::factoryとstd::after_factoryの2つのライブラリ関数です
// 宣言の例 template<typename T, typename... Params, typename Setup> T factory(Params&&... args, Setup &&setup); template<typename F, typename... Params, typename Setup> invoke_result_t<F&&,Params&&> after_factory(F &&f, Params&&... args, Setup &&setup);
パラメータパックの制限によりこのような宣言は行えないのですが、ここでは説明のためにテンプレートパラメータを分けています。
std::factoryは対象の型Tを指定し、そのコンストラクタ引数Params...とセットアップ関数Setupを受け取って、Tの値をParamsで構築したうえでSetupに渡した後の値を返す関数です。
int main(void) { // 使用例 int i = std::factory<int>(52, [](auto &a){ ++a;}); }
std::after_factoryは対象の型の値を生成するファクトリ関数Fとその引数Params...とセットアップ関数Setupを受け取って、FにParamsを渡して生成した値をSetupに渡してから返す関数です。
binary_semaphore Func(int init) { return std::factory<binary_semaphore>(init, [](auto &a){a.release();}); } int main(void) { // 使用例 binary_semaphore bs = std::after_factory(Func, 0, [](auto &a){ a.acquire(); }); // Func()では、binary_semaphoreを初期値0で構築後直ぐに`.release()`を読んでから返す // std::after_factory()では、その値に対してさらに`.acquire()`を読んでから返す bs.release(); bs.acquire(); }
どちらの関数も、巧妙な実装によってRVOを活用することでコピー/ムーブコンストラクタのチェックを回避しています。非常に複雑ですが、提案には実装例が載っています。
最初のような例はstd::factoryを使用することで正しく書き直すことができます。
// 外側のfactory()はいらないかもしれない(例を対応させるために残している) auto factory() -> non_move_and_copy { return std::factory<non_move_and_copy>([](auto& a) { a.init(); }); }
この提案の内容はP2025R2のソリューション(NRVOの必須化)に比較すると劣ったソリューションではありますが、そちらの解決策がいつ利用可能になるか分からないため、それまでの比較的簡易な解決策として利用されることを意図しています。
P3358R0 SARIF for Structured Diagnostics
C++ツールが出力する診断情報の形式としてSARIFの使用を推奨する提案。
SARIF(Static Analysis Results Interchange Format)はOASIS Open projectで標準化されている、静的解析ツールの出力形式を定めたJSONベースのフォーマットです。
SARIFを利用するメリットは以下の点が挙げられます
- 診断情報の標準化
- SARIFは標準化されたフォーマットであるため、異なる静的分析ツールやコンパイラからの出力を統一的に扱うことができる
- これにより、ツール間での診断情報の交換が容易になり、開発者はさまざまなツールから得られた情報を統合的に分析することができるようになる
- 診断情報の機械処理
- 豊富な情報
- SARIFは診断の重大度、メッセージ、ソースコードの位置などの情報を提供することができ、修正方法やヒントなどを標準化された方法で提供することもできる
- 階層型診断
- SARIFは論理階層をもつ診断メッセージを出力できる
- これにより、コンセプトのようなネストした構造に対してその構造を保ったまま診断メッセージを保持することができ、コードのネストした構造に対応した診断メッセージを出力することができる
- 動的な対話
- ツールエコシステム
この文書では、C++ツールとSARIF標準に対して今後取るべき方向性を提示しています
現在のところ、このSARIFの利活用で最も進んでいるのはMSVC(Visual Studio)のようで、2レベルよりも深い階層的診断のサポートや、IDEがそれをストリームで受け取って表示(問題の詳細ウィンドウ)をサポートしています。
この文書は提案というよりはSARIFというフォーマットの周知やC++ツールでのその利用を促すようなもので、Ecosystem ISでこれを標準化したりといったことまでは提案していません。
P3359R0 Slides for P3298R0 - Implicit conversion functions
P3298R0の紹介スライド。
P3298R0では暗黙変換を利用した疑似的なoperator.演算子オーバーロードを可能にするような提案がなされていますが。このスライドは提案の背景や内容について簡単にまとめた紹介(おそらくEWGIのメンバに向けて)するためのものです。
P3360R0 Slides for P3312R0 - Overload Set Types
P3312R0の紹介スライド。
P3312R0の内容を簡単に紹介するとともに、R0の後で判明した問題点とその解決策を報告しています。
報告されている問題は、Overload Set TypeにはADL集合が追加されないことで、ここでは関数名をバッククォートでくくることでADL集合を追加するようにするソリューションを報告しています。
おわり
次月分(2024/08)の記事執筆のお手伝いを募集しています: https://github.com/onihusube/blog/issues/43