文書の一覧
全部で125本あります。
もくじ
- N4966 St. Louis Meeting Invitation and Information
- N4967 WG21 2023-10 Admin telecon minutes
- N4970 WG21 2023-11 Kona Minutes of Meeting
- N4971 Working Draft, Programming Languages -- C++
- N4972 Editors' Report, Programming Languages -- C++
- P0447R24 Introduction of std::hive to the standard library
- P0447R25 Introduction of std::hive to the standard library
- P0447R26 Introduction of std::hive to the standard library
- P0609R2 Attributes for Structured Bindings
- P0952R2 A new specification for std::generate_canonical
- P1028R6 SG14 status_code and standard error object
- P1061R6 Structured Bindings can introduce a Pack
- P1068R10 Vector API for random number generation
- P1673R13 A free function linear algebra interface based on the BLAS
- P1708R8 Basic Statistics
- P1709R4 Graph Library
- P1928R8 std::simd - Merge data-parallel types from the Parallelism TS 2
- P1967R12 #embed - a simple, scannable preprocessor-based resource acquisition method
- P2022R3 Rangified version of lexicographical_compare_three_way
- P2264R6 Make assert() macro user friendly for C and C++
- P2264R7 Make assert() macro user friendly for C and C++
- P2267R1 Library Evolution Policies
- P2308R1 Template parameter initialization
- P2414R2 Pointer lifetime-end zap proposed solutions
- P2447R6 std::span over an initializer list
- P2481R2 Forwarding reference to specific type/template
- P2542R7 views::concat
- P2573R1 = delete("should have a reason");
- P2642R5 Padded mdspan layouts
- P2662R3 Pack Indexing
- P2663R5 Proposal to support interleaved complex values in std::simd
- P2664R5 Proposal to extend std::simd with permutation API
- P2717R4 Tool Introspection
- P2717R5 Tool Introspection
- P2747R1 constexpr placement new
- P2758R1 Emitting messages at compile time
- P2760R1 A Plan for C++26 Ranges
- P2761R0 Slides: If structured binding (P0963R1 presentation)
- P2767R2 flat_map/flat_set omnibus
- P2795R4 Erroneous behaviour for uninitialized reads
- P2806R2 do expressions
- P2810R2 is_debugger_present is_replaceable
- P2810R3 is_debugger_present is_replaceable
- P2819R2 Add tuple protocol to complex
- P2821R5 span.at()
- P2826R1 Replacement functions
- P2827R1 Floating-point overflow and underflow in from_chars (LWG 3081)
- P2830R1 constexpr type comparison
- P2845R5 Formatting of std::filesystem::path
- P2863R3 Review Annex D for C++26
- P2864R2 Remove Deprecated Arithmetic Conversion on Enumerations From C++26
- P2865R4 Remove Deprecated Array Comparisons from C++26
- P2868R3 Remove Deprecated std::allocator Typedef From C++26
- P2869R3 Remove Deprecated shared_ptr Atomic Access APIs From C++26
- P2870R3 Remove basic_string::reserve() From C++26
- P2871R3 Remove Deprecated Unicode Conversion Facets From C++26
- P2878R6 Reference checking
- P2890R1 Contracts on lambdas
- P2890R2 Contracts on lambdas
- P2894R1 Constant evaluation of Contracts
- P2900R2 Contracts for C++
- P2900R3 Contracts for C++
- P2909R3 Fix formatting of code units as integers (Dude, where's my char?)
- P2909R4 Fix formatting of code units as integers (Dude, where's my char?)
- P2918R2 Runtime format strings II
- P2932R2 A Principled Approach to Open Design Questions for Contracts
- P2933R1 std::simd overloads for <bit> header
- P2935R4 An Attribute-Like Syntax for Contracts
- P2952R1 auto& operator=(X&&) = default
- P2961R2 A natural syntax for Contracts
- P2968R1 Make std::ignore a first-class object
- P2968R2 Make std::ignore a first-class object
- P2969R0 Contract annotations are potentially-throwing
- P2977R0 Module commands database format
- P2980R1 A motivation, scope, and plan for a quantities and units library
- P2981R1 Improving our safety with a physical quantities and units library
- P2982R1 std::quantity as a numeric type
- P2984R1 Reconsider Redeclaring static constexpr Data Members
- P2996R1 Reflection for C++26
- P2999R1 Sender Algorithm Customization
- P2999R2 Sender Algorithm Customization
- P2999R3 Sender Algorithm Customization
- P3006R0 Launder less
- P3007R0 Return object semantics in postconditions
- P3016R1 Resolve inconsistencies in begin/end for valarray and braced initializer lists
- P3019R1 Vocabulary Types for Composite Class Design
- P3019R2 Vocabulary Types for Composite Class Design
- P3019R3 Vocabulary Types for Composite Class Design
- P3022R1 A Boring Thread Attributes Interface
- P3023R1 C++ Should Be C++
- P3024R0 Interface Directions for std::simd
- P3025R0 SG14: Low Latency/Games/Embedded/Financial trading/Simulation virtual Minutes to 2023/09/12
- P3026R0 SG19: Machine Learning virtual Meeting Minutes to 2023/07/13
- P3027R0 UFCS is a breaking change, of the absolutely worst kind
- P3028R0 An Overview of Syntax Choices for Contracts
- P3029R0 Better mdspan's CTAD
- P3031R0 Resolve CWG2561: conversion function for lambda with explicit object parameter
- P3033R0 Should we import function bodies to get the better optimizations?
- P3034R0 Module Declarations Shouldn't be Macros
- P3037R0 constexpr std::shared_ptr
- P3038R0 Concrete suggestions for initial Profiles
- P3039R0 Automatically Generate operator->
- P3040R0 C++ Standard Library Ready Issues to be moved in Kona, Nov. 2023
- P3041R0 Transitioning from "#include" World to Modules
- P3042R0 Vocabulary Types for Composite Class Design
- P3043R0 Slides: Using variable template template without meta programming
- P3046R0 Core Language Working Group "ready" Issues for the November, 2023 meeting
- P3050R0 Optimize linalg::conjugated for noncomplex value types
- P3051R0 Structured Response Files
- P3052R0 view_interface::at()
- P3053R0 2023-12 Library Evolution Polls
- P3055R0 Relax wording to permit relocation optimizations in the STL
- P3056R0 what ostream exception
- P3057R0 Two finer-grained compilation model for named modules
- P3059R0 Making user-defined constructors of view iterators/sentinels private
- P3060R0 Add std::ranges::upto(n)
- P3061R0 WG21 2023-11 Kona Record of Discussion
- P3062R0 C++ Should Be C++ - Presentation
- P3066R0 Allow repeating contract annotations on non-first declarations
- P3070R0 Formatting enums
- P3071R0 Protection against modifications in contracts
- P3071R1 Protection against modifications in contracts
- P3072R0 Hassle-free thread attributes
- P3074R0 constexpr union lifetime
- P3075R0 Adding an Undefined Behavior and IFNDR Annex
- おわり
N4966 St. Louis Meeting Invitation and Information
2024年6月24〜29日(米国時間)にかけてアメリカのセントルイスで行われるWG21全体会議の案内。
N4967 WG21 2023-10 Admin telecon minutes
2023年10月27日に行われたWG21管理者ミーティングの議事録
前回(6月)のミーティング以降の各SGの進捗や作業の報告や、11月のKona会議におけるミーティングの予定などが報告されています。
N4970 WG21 2023-11 Kona Minutes of Meeting
2023年11月にハワイのKonaで行われたWG21全体会議の議事録
N4971 Working Draft, Programming Languages -- C++
N4972 Editors' Report, Programming Languages -- C++
↑の変更点をまとめた文書。
P0447R24 Introduction of std::hive
to the standard library
↓
P0447R25 Introduction of std::hive
to the standard library
↓
P0447R26 Introduction of std::hive
to the standard library
要素が削除されない限りそのメモリ位置が安定かつメモリ局所性の高いコンテナであるstd::hive
(旧名std::colony
)の提案。
以前の記事を参照
- P0447R11 Introduction of std::colony to the standard library - [C++]WG21月次提案文書を眺める(2020年12月)
- P0447R12 Introduction of std::colony to the standard library - [C++]WG21月次提案文書を眺める(2021年01月)
- P0447R13 Introduction of std::colony to the standard library - [C++]WG21月次提案文書を眺める(2021年04月)
- P0447R14 Introduction of std::colony to the standard library - [C++]WG21月次提案文書を眺める(2021年05月)
- P0447R15 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2021年06月)
- P0447R16 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2021年09月)
- P0447R17 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2021年11月)
- P0447R18 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2022年01月)
- P0447R19 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2022年02月)
- P0447R20 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2022年06月)
- P0447R21 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2023年02月)
- P0447R22 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2023年05月)
- P0447R23 Introduction of std::hive to the standard library - [C++]WG21月次提案文書を眺める(2023年10月)
R24での変更は
- 代替実装詳細のappendixにある、オーバーアライメントなしで小さい型をサポートする方法についての見直し
shrink_to_fit
の文言を、std::vector
のものに近づける様に変更
R25での変更は
splice
が終端イテレータを無効化することを明確化block_capacity_limits()
にconstexpr
を付加reshape(), shrink_to_fit()
で要素の並べ替えが発生する可能性があるタイミングを明確化するとともに、削減sort()
をlist::sort()
と調和する様に変更- 標準の言葉の表現と一貫するように、"shall be"を"is"に、"into hive"を"into *this"に修正
reshape()
がキャパシティを変更する可能性があることを追記- 他の部分でカバーされているため、
sort()
の例外に関する記述を削除
このリビジョンでの変更は
is_active()
を削除get_iterator()
に事前条件が追加され、効果の指定を削除- googleグループのリンク更新
- 代替実装ガイドラインを代替実装のappendixへ移動
- よくある質問と、委員会からの一部の質問への回答をappendixにまとめた
- 最初のリファレンス実装と現在の実装に関するメモとベンチマークをappendixにまとめた
- 委員会への質問セクションを削除し、簡単な定義セクションに置き換え
- 負の値を処理できる
distance()
への参照を削除 size()
を持たないことについての情報を、Design DecisionsからFAQへ移動- 時間計算量のappendixを削除し、個々の関数のDesign Decisionsセクションへ移動
- 正確さの向上のため、オーバーアライメントをストレージを人工的に広げる、に変更
- 代替実装appendixのビットフィールド+ジャンプカウントをより小さな型をカバーできる様に変更
- 非常に小さな型をサポートするための3つのより良いアプローチについて代替実装appendixに追記
- FAQにslot mapとの比較に関するセクションを追加
などです。
この提案は、LEWGでのレビューと投票を終えて、LWGに転送されています。
P0609R2 Attributes for Structured Bindings
構造化束縛の個々の名前に属性を指定できるようにする提案。
構造化束縛宣言には属性を指定することができますが、その属性が作用するのは構造化束縛宣言の裏に隠れている分解対象のオブジェクトであり、導入されている個々の名前ではありません。
auto f() -> std::tuple<int, double, char>; int main() { // この属性指定はf()の戻り値(見えていない)に対するもの [[maybe_unused]] auto [a, b, c] = f(); }
構造化束縛対象そのものに対してアライメントを指定するなど、この指定にはユースケースがあります。
しかし一方で、構造化束縛宣言の個々の名前に対して属性を指定する方法はありません。標準属性で使用可能かつ意味があるのは[[maybe_unused]]
のみですが、コンパイラベンダなどが提供する多くのアノテーション属性などを考慮すると、それを行いたい動機付けは大きくなる可能性があります。
この提案は、構造化束縛宣言内のそれぞれの名前に対して直接属性指定を行えるように文法を拡張しようとするものです。
提案されている構文は次のようなものです
auto f() -> std::tuple<int, double, char>; int main() { // cにのみ[[maybe_unused]]を指定 auto [a, b, [[maybe_unused]] c] = f(); }
構造化束縛宣言の[]
の中で名前に対して直接属性を指定できるようにしています。最初の名前に指定する場合[[[
のように角括弧が連続する可能性はありますが、構文は他の場所での属性指定構文と一貫しています。
P0952R2 A new specification for std::generate_canonical
std::generate_canonical
の仕様を改善する提案。
以前の記事を参照
このリビジョンでの変更は、提案する文言に、アルゴリズム指定の式中のR
についての注記を追加したことです。
この提案は2023年11月のKona会議で採択され、C++26ドラフトに取り込まれています。
P1028R6 SG14 status_code
and standard error object
現在の<sysytem_error>
にあるものを置き換える、エラーコード/ステータス伝搬のためのライブラリ機能の提案。
以前の記事を参照
- P1028R4 SG14 status_code and standard error object - [C++]WG21月次提案文書を眺める(2022年11月)
- P1028R5 SG14 status_code and standard error object - [C++]WG21月次提案文書を眺める(2023年05月)
このリビジョンでの変更は
errc::success
をerrc::invalid
に変更status_code_domain
にstring_view
から構築するconstexpr
コンストラクタを追加status_code_domain
のdo_*()
系protected
メンバ関数の_
を削除status_code_domain
に<=>
を追加status_code_domain
はトリビアルコピー可能ではなくなった- 型消去されたステータスコードに対しては、通常のコピーコンストラクタではなく
status_code(in_place_t, const status_code<void> & v)
を使用する様に変更
などです。
P1061R6 Structured Bindings can introduce a Pack
構造化束縛可能なオブジェクトをパラメータパックに変換可能にする提案。
以前の記事を参照
- P1061R2 Structured Bindings can introduce a Pack - WG21月次提案文書を眺める(2022年04月)
- P1061R3 Structured Bindings can introduce a Pack - WG21月次提案文書を眺める(2022年10月)
- P1061R4 Structured Bindings can introduce a Pack - WG21月次提案文書を眺める(2023年02月)
- P1061R5 Structured Bindings can introduce a Pack - WG21月次提案文書を眺める(2023年05月)
このリビジョンでの変更は、提案する文言の変更とより複雑な例の追加などです。
この提案は、現在CWGのレビュー受けています。
P1068R10 Vector API for random number generation
<random>
にある既存の分布生成器にイテレータ範囲を乱数で初期化するAPIを追加する提案。
以前の記事を参照
- P1068R4 : Vector API for random number generation - [C++]WG21月次提案文書を眺める(2020年7月)
- P1068R5 Vector API for random number generation - [C++]WG21月次提案文書を眺める(2021年05月)
- P1068R6 Vector API for random number generation - [C++]WG21月次提案文書を眺める(2022年10月)
- P1068R7 Vector API for random number generation - [C++]WG21月次提案文書を眺める(2023年05月)
- P1068R8 Vector API for random number generation - [C++]WG21月次提案文書を眺める(2023年08月)
- P1068R9 Vector API for random number generation - [C++]WG21月次提案文書を眺める(2023年09月)
このリビジョンでの変更は、
- ADLの代わりに非静的メンバ関数を探索するようにCPOの動作を変更
std::ranges::generate_random
が一時オブジェクトなエンジンと分布生成器をサポートする様に変更(フォーワーディングリファレンスの使用による)
などです。
この提案はLEWGのレビューを通過し、LWGへ転送されています。
P1673R13 A free function linear algebra interface based on the BLAS
標準ライブラリに、BLASをベースとした密行列のための線形代数ライブラリを追加する提案。
以前の記事を参照
- P1673R3 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2021年04月)
- P1673R4 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2021年08月)
- P1673R5 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2021年10月)
- P1673R6 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2021年12月)
- P1673R7 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2022年04月)
- P1673R8 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2022年05月)
- P1673R9 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2022年06月)
- P1673R10 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2022年10月)
- P1673R11 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2023年01月)
- P1673R12 A free function linear algebra interface based on the BLAS - [C++]WG21月次提案文書を眺める(2023年04月)
このリビジョンでの変更は多岐に渡りますが、LWGのレビューを受けての文言の細かい調整がメインです。
この提案は、2023年11月のKona会議で全体投票を通過し、C++26ドラフトに取り込まれています。
P1708R8 Basic Statistics
標準ライブラリにいくつかの統計関数を追加する提案。
以前の記事を参照
- P1708R3 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2021年01月)
- P1708R4 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2021年04月)
- P1708R5 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2021年06月)
- P1708R6 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2022年03月)
- P1708R7 Basic Statistics - [C++]WG21月次提案文書を眺める(2023年02月)
このリビジョンでの変更は
などです。
P1709R4 Graph Library
グラフアルゴリズムとデータ構造のためのライブラリ機能の提案。
以前の記事を参照
このリビジョンでは、4年分の経験や検討を反映した大規模な再設計が行われています。その変更は
- 考慮すべきアルゴリズムの再確認
- 外向きエッジを持つ隣接リスト、エッジリスト、remove/mutableインターフェースに焦点を絞って、提案の範囲を縮小
- directed/undirectedコンセプトをグラフ型に対する順序なしエッジのオーバーロード可能な型、に置き換え
- グラフコンテナ型と関数を単純化
- 特に、
const
/非const
の変種を1つの定義に統合し、必要に応じて両方の場合を扱える様にした
- 特に、
- 全てのグラフコンテナインターフェースはカスタマイズポイントとなった
- NWGraphライブラリの設計からインスピレーションを得たviewを導入し、グラフをトラバースするためのよりシンプルでクリーンなインターフェースを実現し、コンテナインターフェースの設計を簡素化
- 二部グラフと多部グラフのサポート追加
- 2つのコンテナ実装を、高性能グラフ処理でよく使用されているデータ構造であるCompressed Sparse Rowに基づく圧縮グラフに置き換え
などです。
このリビジョンでは特に、Boost.Graphの経験を踏まえてC++20で作成されたNWGraphライブラリにおける経験を取り込んでいます。NWGraphでは、範囲の範囲としてのグラフを定義し、その抽象の下でいくつかのグラフアルゴリズムを実装しています。このリビジョンでは、その設計の利点やアルゴリズム実装を取り込むことで以前のAPIを進化させています。
一方、NWGraphには既に使用されている任意のグラフデータ構造を使用可能にするためのAPIが欠けており、この提案では以前のリビジョンからのものを発展させてその部分を補っています。
P1928R8 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月)
このリビジョンでの変更は
reduce_min_index/reduce_max_index
の戻り値としてstd::optional
を返すAPIの検討- CV修飾されていない算術型、をより明確な型のリストに置き換え
- その他文章と文言の修正
などです。
P1967R12 #embed
- a simple, scannable preprocessor-based resource acquisition method
コンパイル時(プリプロセス時)にバイナリデータをインクルードするためのプリプロセッシングディレクティブ#embed
の提案。
以前の記事を参照
- P1967R3
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2021年04月) - P1967R4
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2021年06月) - P1967R5
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2021年04月) - P1967R6
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2022年05月) - P1967R7
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2022年06月) - P1967R8
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2022年07月) - P1967R9
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2022年10月) - P1967R10
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2023年01月) - P1967R11
#embed
- a simple, scannable preprocessor-based resource acquisition method - [C++]WG21月次提案文書を眺める(2023年08月)
このリビジョンでの変更は
embed-element-width
を削除し、適切なCHAR_BIT
に置き換え- マクロ展開の方法を変更することでマクロ展開の問題の解消を図る
などです。
この提案は現在CWGのレビュー中です。
P2022R3 Rangified version of lexicographical_compare_three_way
std::lexicographical_compare_three_way
のRange版を追加する提案。
以前の記事を参照
- P2022R0 Rangified version of
lexicographical_compare_three_way
- [C++]WG21月次提案文書を眺める(2022年02月) - P2022R1 Rangified version of
lexicographical_compare_three_way
- [C++]WG21月次提案文書を眺める(2023年04月) - P2022R2 Rangified version of
lexicographical_compare_three_way
- [C++]WG21月次提案文書を眺める(2023年05月)
このリビジョンでの変更は、same_as_any_of
コンセプトを<concepts>
に移動したこと、インターフェースを再考したことなどです。
P2264R6 Make assert()
macro user friendly for C and C++
↓
P2264R7 Make assert()
macro user friendly for C and C++
assert
マクロをC++の構文に馴染むように置き換える提案。
- P2264R0 Make
assert()
macro user friendly for C and C++ - WG21月次提案文書を眺める(2020年12月) - P2264R2 Make
assert()
macro user friendly for C and C++ - WG21月次提案文書を眺める(2021年10月) - P2264R3 Make
assert()
macro user friendly for C and C++ - WG21月次提案文書を眺める(2022年03月) - P2264R4 Make
assert()
macro user friendly for C and C++ - WG21月次提案文書を眺める(2022年08月) - P2264R5 Make
assert()
macro user friendly for C and C++ - WG21月次提案文書を眺める(2023年09月)
R6での変更は、条件式のbool
への変換に際して、スコープ付き列挙型の値の変換を抑制する巧妙なトリックの採用によって<type_traits>
への依存等の懸念を解消したことです。
このリビジョンでの変更は、LWGのレビューを受けての文言の修正です。
R5では、assert
マクロのオペランドを明示的bool
変換することで渡された条件式の評価結果をbool
値として取得していました。ただし、そうしてしまうとスコープ付き列挙型の値が渡された場合にもbool
値に変換できてしまうためこれを防止するためのトリックが必要だったのですが、そのトリックのためには<type_traits>
への依存関係や追加のラップ関数等が必要となり、それが懸念されていました。
この問題に対して、スコープ付き列挙値の変換を防ぎつつ他のものはbool
に変換する次のようなトリックがフィードバックとして寄せられました
#define assert(...) ((__VA_ARGS__) ? (void)sizeof(bool(__VA_ARGS__)) : (void)__assert_fail(#__VA_ARGS__, __FILE__, __LINE__))
条件演算子の第一オペランドで、文脈的bool
変換によって渡された条件式の結果をbool
値に変換しています。文脈的bool
変換はif
のオペランドで行われるのと等価の変換で、暗黙変換であるためスコープ付き列挙値をbool
値に変換することができません。
R6ではこのトリックの採用を前提として、明示的bool
変換の代わりに文脈的bool
変換によって渡された条件式の結果を取得するように文言を修正しています。
この提案は、2023年11月のKona会議にて全体会議で採択され、C++26に採用されています。
P2267R1 Library Evolution Policies
C++標準ライブラリ設計のためのポリシーについて検討する提案。
以前の記事を参照
このリビジョンでの変更は
- 以前に行った作業のリストに提案を追加
- LEWGからのフィードバック(ポリシーを採用することで一貫性が向上し時間が節約される根拠)を追加
などです。
P2308R1 Template parameter initialization
非型テンプレートパラメータの初期化に関しての規定を充実させる提案。
以前の記事を参照
このリビジョンでの変更は
- NTTPの模範となる値の宣言に
constexpr
を付加 - テンプレートパラメータオブジェクトの制約と選択を明確化し、模範(exemplar)という用語を削除
などです。
このリビジョンでは、以前に使用されていた模範(exemplar)という用語は削除され、代わりに初期化子候補(candidate initializer)という用語が導入されています(その意味するところは若干異なっていますが)。
P2414R2 Pointer lifetime-end zap proposed solutions
Pointer lifetime-end zapと呼ばれる問題の解決策の提案。
以前の記事を参照
- P2414R0 Pointer lifetime-end zap proposed solutions - WG21月次提案文書を眺める(2021年07月)
- P2414R0 Pointer lifetime-end zap proposed solutions - WG21月次提案文書を眺める(2021年08月)
このリビジョンでの変更は
- 在野のLIFOプッシュアルゴリズムの調査に基づく更新
- LIFOプッシュライブラリが次のスタックノードへのポインタに直接アクセスできないという事実について
- 選択されていないオプションを削除して、特定のソリューションに焦点を当てる
- ソースコード内の特定の明確にマークされたポインタのみが、実装がポインタの無効性を再検討できる様にするアプローチのみに焦点を当てている
などです。
P2447R6 std::span
over an initializer list
std::span
にinitializer_list
を受け取るコンストラクタを追加する提案。
以前の記事を参照
- P2447R0 std::span and the missing constructor - WG21月次提案文書を眺める(2021年09月)
- P2447R1 std::span and the missing constructor - WG21月次提案文書を眺める(2021年12月)
- P2447R2 std::span and the missing constructor - WG21月次提案文書を眺める(2022年01月)
- P2447R3 std::span and the missing constructor - WG21月次提案文書を眺める(2023年04月)
- P2447R4 std::span and the missing constructor - WG21月次提案文書を眺める(2023年05月)
- P2447R5
std::span
over an initializer list - WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は、コンストラクタからnoexcept
を削除したことです。
この提案は既に、2023年11月のKona会議で全体投票を通過し、C++26WDに取り込まれています。
P2481R2 Forwarding reference to specific type/template
テンプレートパラメータ指定時にconst
と値カテゴリを推論可能にする構文の必要性について説明した文書。
このリビジョンでの変更は、EWGにおける投票結果を追記したことと、提案する対象を絞ったことなどです。
EWGにおける投票では、この問題の解決の手段として新しい転送参照(forwarding reference)を求める意見が明確化された様です。
これを受けて、この提案は新しい転送参照として提案する対象を2つに絞っています。
1つは以前から提示されていたT auto&&
形式
void f(std::string auto&& a); template <typename... Ts> void g(std::tuple<Ts...> auto&& b); template <typename T> void h(T auto&& c); template <typename T> void i(T auto& d);
もう一つはこの提案で提示されたforward T
の形式
void f(forward std::string a); template <typename... Ts> void g(forward std::tuple<Ts...> b); template <typename T> void h(forward T c); template <typename T> void i(forward T& d);
forward T
の形式T auto&&
とほぼ同じように使用でき同じ利点がありますが、concept auto
と構文が異なることで異なる動作をすることが明確になる点が改善されています。ただし、他の欠点(decltype()
を使用しないと型を取得できない)はそのままであり、またforward
というキーワードが一般的すぎる点などが欠点として追加されます。
P2542R7 views::concat
同じ要素型を持つ異なる型の範囲を連結するRangeファクトリ、views::concat
の提案。
以前の記事を参照
- P2542R0
views::concat
- WG21月次提案文書を眺める(2022年02月) - P2542R1
views::concat
- WG21月次提案文書を眺める(2022年04月) - P2542R2
views::concat
- WG21月次提案文書を眺める(2022年05月) - P2542R3
views::concat
- WG21月次提案文書を眺める(2023年07月) - P2542R4
views::concat
- WG21月次提案文書を眺める(2023年09月) - P2542R5
views::concat
- WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は、
!common_range && random_access_range && sized_range
のような範囲をサポートしないことを文言に適用const
変換コンストラクタを修正- 文言の修正
などです。
この提案はLEWGのレビューを終えて、LWGに転送されています。
P2573R1 = delete("should have a reason");
関数のdelete
指定にメッセージを付加できるようにする提案。
以前の記事を参照
このリビジョンでの変更は
- C++26をターゲットとした
- ベースとなるドラフトの更新と、関連する提案の追記
- 以前の同様の提案であるN4186の投票結果を追記
などです。
P2642R5 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月)
このリビジョンでの変更は
- 機能テストマクロを削除して、
__cpp_lib_submdspan
をバンプアップするように変更 - P2630R3(
submdspan
)の内容を適用 - 実装経験などを更新
などです。
この提案はLEWGのレビューを終えて、LWGへ転送されています。
P2662R3 Pack Indexing
パラメータパックにインデックスアクセスできるようにする提案。
以前の記事を参照
- P2662R0 Pack Indexing - [C++]WG21月次提案文書を眺める(2022年10月)
- P2662R1 Pack Indexing - [C++]WG21月次提案文書を眺める(2023年05月)
- P2662R2 Pack Indexing - [C++]WG21月次提案文書を眺める(2023年07月)
このリビジョンでの変更はCWGレビューを受けての文言の改善です。
この提案はすでに2023年11月の全体会議で採択され、C++26に取り込まれています。
P2663R5 Proposal to support interleaved complex values in std::simd
std::simd
でstd::complex
をサポートできるようにする提案。
以前の記事を参照
- P2663R0 Proposal to support interleaved complex values in
std::simd
- WG21月次提案文書を眺める(2022年10月) - P2663R1 Proposal to support interleaved complex values in
std::simd
- WG21月次提案文書を眺める(2023年02月) - P2663R3 Proposal to support interleaved complex values in
std::simd
- WG21月次提案文書を眺める(2023年05月) - P2663R4 Proposal to support interleaved complex values in
std::simd
- WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は、std::complex
の浮動小数点数型の特殊化のみが許可されることを明確にしたこと、real/imag
セッターのフリー関数を考慮するオプションを削除しメンバ関数のみを考慮するようにしたことです。
この提案はLEWGのレビューを終えて、LWGへ転送されています。
P2664R5 Proposal to extend std::simd
with permutation API
std::simd
に、permute操作のサポートを追加する提案。
以前の記事を参照
- P2664R0 Proposal to extend
std::simd
with permutation API - WG21月次提案文書を眺める(2022年11月) - P2664R1 Proposal to extend
std::simd
with permutation API - WG21月次提案文書を眺める(2023年02月) - P2664R3 Proposal to extend
std::simd
with permutation API - WG21月次提案文書を眺める(2023年05月) - P2664R4 Proposal to extend
std::simd
with permutation API - WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は
gather
とscatter
をそれぞれgather_from
とscatter_to
に変更gather_from
とscatter_to
にマスキングオーバーロードを追加- メモリの動作を制御するために、
gather_from
とscatter_to
にフラグを追加 gather_from
とscatter_to
のメリットについて追記simd_split
やsimd_cat
に新しい名前を使用するよう切り替え
などです。
P2717R4 Tool Introspection
↓
P2717R5 Tool Introspection
C++周辺ツールが、Ecosystem ISにどれほど準拠しているのかを互いに通信する手段を標準化する提案。
以前の記事を参照
- P2717R0 Tool Introspection - WG21月次提案文書を眺める(2023年01月)
- P2717R1 Tool Introspection - WG21月次提案文書を眺める(2023年05月)
- P2717R2 Tool Introspection - WG21月次提案文書を眺める(2023年07月)
- P2717R3 Tool Introspection - WG21月次提案文書を眺める(2023年10月)
R4での変更は、ツールにとっての後方互換性の意味についての説明を追加したことです。
このリビジョンでの変更は、機能名の区切り文字(コマンドオプションではなく、返すJSONのキー名)をドッド(.
)に変更し、文言をEcosystem ISドラフトにマージしたことなどです。
P2747R1 constexpr placement new
定数式において、placement newの使用を許可する提案。
以前の記事を参照
このリビジョンでは、以前に提案していた3つのことのうち1つ(placement newの定数式での許可)にのみ提案を絞ったことです。
以前のこの提案では
void*
からの適切なポインタキャストを定数式で許可する- 定数式でplacement newを許可する
- 未初期化オブジェクトの配列の取り扱いの改善
の3つを提案していました。1はP2738R1の採択によって解決され、3は本質的に別の問題であるため分離され他のところで対処されようとしています(P3074R0など)。
そのため、この提案は2の解決にのみ対象を絞っています。
定数式でのplacement newを行う関数としては、std::construct_at
が既に存在しています。しかし、この関数による初期化方法は非常に限定されています。
初期化方法 | placement new | construct_at() |
---|---|---|
値初期化 | new (p) T(args...) |
std::construct_at(p, args...) |
デフォルト初期化 | new (p) T |
できない |
リスト初期化 | new (p) T{a, b} |
できない |
指示付き初期化 | new (p) T{ .a=a, .b=b } |
できない |
また、ライブラリ関数であるためにコピー省略を妨げる問題もあります。
auto get_object() -> T; void construct_into(T* p) { // get_object()の結果をムーブして構築 std::construct_at(p, get_object()); // get_object()の結果から直接構築 :::new (p) T(get_object()); }
placement newが定数式で禁止されていたのはポインタをvoid*
で受け取るためほぼなんでもできてしまうためで、それを回避するためにstd::construct_at
という限定された機能を持つ関数が導入されていました。
しかし、定数式ではポインタの正しい型を追跡することができ、placement newができることを制限することができます。この能力を使用することでvoid*
からのキャスト(static_cast<T*>(static_cast<void*>(p))
)も許可されており、定数式でならplacement newを安全に使用することができます。
P2758R1 Emitting messages at compile time
コンパイル時に任意の診断メッセージを出力できるようにする提案。
以前の記事を参照
このリビジョンでの変更は、P2741R3と重複する内容を削除したことです。
以前のリビジョンでは、static_assert
の第二引数に文字列範囲を渡せるようにすることとコンパイル時メッセージ出力のためのライブラリ関数の2つの事を提案していました。前者はP2741がC++26に採択されたことで不要になったため、このリビジョンでは後者のライブラリ機能だけに的を絞っています。
P2760R1 A Plan for C++26 Ranges
C++26に向けての、<ranges>
ライブラリ関連作業の予定表。
以前の記事を参照
このリビジョンでの変更は、output_iterator
の改善と並行アルゴリズムサポートについてを優先度1に追加した事です。
output_iterator
の改善とは、T*
のように入力イテレータでもある出力イテレータに対して、back_insert_iterator
のように出力だけしかできない出力イテレータを区別することです。それを行うことで、出力イテレータの定義を簡略化するとともに出力動作を効率化する機会を提供できるためです。
出力イテレータは典型的には次のように使用されます
template <typename InputIt, typename OutputIt> void copy(InputIt first, InputIt last, OutputIt out) { for (; first != last; ++first) { *out++ = *first; } }
out
が出力イテレータですが、これは入力イテレータよりも明らかに必要な操作が少ないことが分かります。これを反映して、back_insert_iterator
を例えば次のように実装できるかもしれません。
template <typename C> class back_inserter { C* cont_; public: explicit back_inserter(C& c) : cont_(&c) { } // these do nothing auto operator*() -> back_inserter& { return *this; } auto operator++() -> back_inserter& { return *this; } auto operator++(int) -> back_inserter { return *this; } // this one does something auto operator=(typename C::value_type const& val) -> back_inserter& { cont_->push_back(val); return *this; } // same auto operator=(typename C::value_type&& val) -> back_inserter& { ... } };
この実装は有効ではありますが、冗長な関数をいくつも記述しなければならないなど面倒な部分が多数あります(本来=
のみでいいはず)。
そして何より、出力イテレータの出力が要素を一個づつ出力していくことしか考慮していないことが、出力パフォーマンスを低下させています。入力のサイズが分かっている場合、reserve()
したりC++23の範囲挿入関数を使用するなどしてより出力操作を効率化できる可能性があります。しかし、現在の出力イテレータの定義はその機会を提供していません。
出力専用のイテレータを定義することで、出力イテレータの実装簡易化と効率的な出力経路の提供が同時に達成できます。
P2761R0 Slides: If structured binding (P0963R1 presentation)
P0963R1の紹介スライド。
P0963R1については以前の記事を参照
EWGIのメンバに向けて、P0963R1で提案されている機能のモチベーションや動作について説明するものです。
P2767R2 flat_map/flat_set
omnibus
flat_map
/flat_set
の仕様にあるいくつかの問題点とその解決策について報告する提案。
以前の記事を参照
- P2767R0 flat_map/flat_set omnibus - WG21月次提案文書を眺める(2023年05月)
- P2767R1 flat_map/flat_set omnibus - WG21月次提案文書を眺める(2023年07月)
このリビジョンでの変更は
- LWGを対象とするものとLEWGを対象とするものに分割し、並べ替えた
- 1つの提案で一度に解決されるサブセクションを統合
- 多くの例を前後比較するテーブルに置き換えた
- コンテナのゼロ初期化についてを追加
- 内部コンテナを値初期化していることで一部のコンテナでは非効率になる可能性がある
などです。
P2795R4 Erroneous behaviour for uninitialized reads
未初期化変数の読み取りに関して、Erroneous Behaviourという振る舞いの規定を追加する提案。
以前の記事を参照
- P2795R2 Erroneous behaviour for uninitialized reads - WG21月次提案文書を眺める(2023年07月)
- P2795R2 Erroneous behaviour for uninitialized reads - WG21月次提案文書を眺める(2023年08月)
このリビジョンでの変更は、
- 再び、対象をすべての自動変数(一時オブジェクトを含む)に戻した
std::bit_cast
に誤った値(EBとして読み取られた値)を処理するための文言を追加- オブジェクト表現がその型に対して有効ではない場合、誤った動作の後で未定義動作が発生する可能性がある事を明確化
- 関数パラメータに対するオプトアウト属性指定は、関数の最初の宣言に指定する必要があることを明確化
- 誤った動作が発生する状況を定義するために使用される標準のフレーズを確立するために文言を更新
などです。
この提案は現在CWGのレビュー中です。
P2806R2 do expressions
値を返せるスコープを導入するdo
式の提案。
以前の記事を参照
このリビジョンでの変更は、do
式からのreturn
をdo return ...
からdo_return ...
へ変更した(曖昧さを解消するため)ことと生存期間に関するセクションを追加したことなどです。
P2810R2 is_debugger_present
is_replaceable
↓
P2810R3 is_debugger_present
is_replaceable
P2546で提案されているis_debugger_present()
をユーザーが置換可能にする提案。
以前の記事を参照
- P2810R0
is_debugger_present
is_replaceable - WG21月次提案文書を眺める(2023年02月) - P2810R1
is_debugger_present
is_replaceable - WG21月次提案文書を眺める(2023年07月)
R2での変更は、2023年9月のLEWGにおける投票結果を追記し、それを反映してユーザー置換関数に事前条件を付加しないように修正した事です。
このリビジョンでの変更は、提案する文言から問題のあった注記を削除した事です。
この提案はLEWGのレビューを終えてLWGに転送されています。
P2819R2 Add tuple protocol to complex
std::complex
にtuple
インターフェースを追加する提案。
以前の記事を参照
- P2819R0 Add tuple protocol to complex - WG21月次提案文書を眺める(2023年04月)
- P2819R1 Add tuple protocol to complex - WG21月次提案文書を眺める(2023年07月)
このリビジョンでの変更は
- 専用の機能テストマクロを削除
- Hidden friendな
get()
はtuple-likeでは動作しなかったため、フリー関数に戻した - Annex Cの文言を削除
などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2821R5 span.at()
std::span
に.at()
メンバ関数を追加する提案。
以前の記事を参照
- P2821R0
span.at()
- WG21月次提案文書を眺める(2023年04月) - P2821R1
span.at()
- WG21月次提案文書を眺める(2023年05月) - P2821R3
span.at()
- WG21月次提案文書を眺める(2023年07月) - P2821R4
span.at()
- WG21月次提案文書を眺める(2023年08月)
このリビジョンでの変更は、余分なフリースタンディングコメントを削除したことです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2826R1 Replacement functions
ある関数を指定したシグネチャでそのオーバーロード集合に追加できるようにする、一種の関数エイリアスの提案。
以前の記事を参照
このリビジョンでの変更はよく分かりませんが、文書の構成を整理していくつか例を追加しているようです。
P2827R1 Floating-point overflow and underflow in from_chars (LWG 3081)
std::from_chars
で浮動小数点数を変換する際にアンダーフローを検出できるようにする提案。
以前の記事を参照
このリビジョンでの変更は、提案する文言を書き直したことです。
P2830R1 constexpr type comparison
std::type_info::before()
をconstexpr
にする提案。
以前の記事を参照
このリビジョンでの変更は
std::type_info::before
の変更を行わないオプションを追加- 匿名名前空間を空にすることができないことを明確化
- FAQセクションを追加
- 実用的なサンプルコードを追加
- 提案する構文を追加
- appendixを追加
などです。
この提案ではオプションとして次の5つを提示しています
std::type_info::before
にconstexpr
を付加- 利点
- 新しいトークンが必要ない
- 発見されやすい
- 組み込みの
type-erasure
であること
- 欠点
- ABI破壊
- 多くの場所で禁止されている
<typeinfo>
をインクルードする必要がある - NTTPに対して使用できない
- 利点
std::strong_order
にtype_info
比較のためのオーバーロード追加- 利点
- 新しいトークンが必要ない
- 欠点
<compare>
で<typeinfo>
のインクルードが必要になる- NTTPに対して使用できない
- 利点
std::entity_ordering
変数テンプレートの導入- 利点
- 新しい名前であり、明確にコンパイル時に利用可能
<typeinfo>
のインクルードが必要ない
- 欠点
- 新しい名前であること
- 発見されづらい
- 利点
std::type_identity
にoperator<=>
を追加- 利点
- 若干やることが明白
- 欠点
<type_traits>
が<compare>
に依存するようになる- NTTPに対して使用できない
- 利点
- ユニバーサルテンプレートパラメータを用いた
std::__lift::operator<=>
を導入- 利点
- 強いて言うなら、そのうちこの
__lift
のようなものが必要になるかもしれない
- 強いて言うなら、そのうちこの
- 欠点
- 何をするか明確ではない
- 新しい名前であること
- 発見されづらい
- 本質的に別の
type_info
を追加している
- 利点
3つ目のstd::entity_ordering
とは次のような変数テンプレートです。
template <universal template T, universal template U> inline constexpr std::strong_ordering entity_ordering = ORDER(T, U);
すなわち、std::entity_ordering<T, U> < 0
のようにしてT, U
の順序付比較が行えます。
P2845R5 Formatting of std::filesystem::path
std::filesystem::path
をstd::format()
でフォーマット可能にする提案。
以前の記事を参照
- P2845R0 Formatting of
std::filesystem::path
- WG21月次提案文書を眺める(2023年05月) - P2845R1 Formatting of
std::filesystem::path
- WG21月次提案文書を眺める(2023年07月) - P2845R2 Formatting of
std::filesystem::path
- WG21月次提案文書を眺める(2023年08月) - P2845R4 Formatting of
std::filesystem::path
- WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は、「無効なコード単位」をより具体的な「不適格な部分列の最大部分」に置き換えたこと、LEWGでの投票結果を追記したことです。
P2863R3 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月)
このリビジョンでの変更は、関連提案のステータス更新や、その表記法の変更などです。
P2864R2 Remove Deprecated Arithmetic Conversion on Enumerations From C++26
C++20の一貫比較仕様に伴って非推奨とされた、列挙値から算術型への暗黙変換を削除する提案。
以前の記事を参照
- P2864R0 Remove Deprecated Arithmetic Conversion on Enumerations From C++26 - WG21月次提案文書を眺める(2023年05月)
- P2864R1 Remove Deprecated Arithmetic Conversion on Enumerations From C++26 - WG21月次提案文書を眺める(2023年08月)
このリビジョンでの変更は
- Kona会議でのEWGのレビューの記録を追加
- いくつかのセクションの並べ替え
- 非推奨警告についての調査を更新
- ベースとなるドラフトの更新
- Annex Cのテキスト修正
などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2865R4 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月)
このリビジョンでの変更は
- 最新のWDに追随
- 委員会での進捗を追記
- C互換性について追記
- 非推奨警告の調査を更新
などです。
P2868R3 Remove Deprecated std::allocator
Typedef From C++26
std::allocator
にある非推奨化された入れ子型定義を削除する提案。
以前の記事を参照
- P2868R0 Remove Deprecated
std::allocator
Typedef From C++26 - WG21月次提案文書を眺める(2023年05月) - P2868R1 Remove Deprecated
std::allocator
Typedef From C++26 - WG21月次提案文書を眺める(2023年08月) - P2868R2 Remove Deprecated
std::allocator
Typedef From C++26 - WG21月次提案文書を眺める(2023年09月)
このリビジョンでの変更は、最新のWDに追随したことと、Annex Cの修正などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2869R3 Remove Deprecated shared_ptr
Atomic Access APIs From C++26
C++20で非推奨とされた、std::shared_ptr
のアトミックフリー関数を削除する提案。
以前の記事を参照
- P2869R0 Remove Deprecated
shared_ptr
Atomic Access APIs From C++26 - WG21月次提案文書を眺める(2023年05月) - P2869R1 Remove Deprecated
shared_ptr
Atomic Access APIs From C++26 - WG21月次提案文書を眺める(2023年08月) - P2869R2 Remove Deprecated
shared_ptr
Atomic Access APIs From C++26 - WG21月次提案文書を眺める(2023年09月)
このリビジョンでの変更は全体的な修正などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2870R3 Remove basic_string::reserve()
From C++26
C++20で非推奨とされたstd::string::reserve()
をC++26に向けて削除する提案。
以前の記事を参照
- P2870R0 Remove
basic_string::reserve()
From C++26 - WG21月次提案文書を眺める(2023年05月) - P2870R1 Remove
basic_string::reserve()
From C++26 - WG21月次提案文書を眺める(2023年08月) - P2870R2 Remove
basic_string::reserve()
From C++26 - WG21月次提案文書を眺める(2023年09月)
このリビジョンでの変更は、最新のWDに追随したことと、Annex Cの修正などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2871R3 Remove Deprecated Unicode Conversion Facets From C++26
C++17で非推奨とされた<codecvt>
ヘッダをC++26で削除する提案。
以前の記事を参照
- P2871R0 Remove Deprecated Unicode Conversion Facets From C++26 - WG21月次提案文書を眺める(2023年05月)
- P2871R1 Remove Deprecated Unicode Conversion Facets From C++26 - WG21月次提案文書を眺める(2023年08月)
- P2871R2 Remove Deprecated Unicode Conversion Facets From C++26 - WG21月次提案文書を眺める(2023年09月)
このリビジョンでの変更は
- 最新のWDに追随した
- 互換性の文言を更新し、ヘッダユニットのインポートについて言及
- C++03との差分にある
<codecvt>
ヘッダ周りの参照を削除
などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2878R6 Reference checking
プログラマが明示的に関数の戻り値に関するライフタイム注釈を行えるようにする提案。
以前の記事を参照
- P2878R1 Reference checking - WG21月次提案文書を眺める(2023年05月)
- P2878R4 Reference checking - WG21月次提案文書を眺める(2023年07月)
- P2878R5 Reference checking - WG21月次提案文書を眺める(2023年08月)
このリビジョンでの変更は
などです。
P2890R1 Contracts on lambdas
↓
P2890R2 Contracts on lambdas
ラムダ式に対する契約条件指定ができるようにする提案。
以前の記事を参照
R1での変更は、キャプチャの問題を解決するための別のオプションを追加したことです。
このリビジョンでの変更は、無意味な名前探索ルールを修正したことです。
ラムダ式で契約注釈を使用可能にする際に最も問題となるのは、デフォルトキャプチャ使用時に契約注釈内部だけで使用されている外部エンティティを暗黙的にキャプチャするかどうかです。
constexpr auto f(int i) { return sizeof( [=] [[pre: i > 0]] {}); // 戻り値はどうなる? } constexpr auto g(int i) { return sizeof( [=] { [[assume (i > 0)]]; } ); // 戻り値はsizeof(int) }
R0では契約注釈だけで使用されているラムダ式外部の変数はデフォルトキャプチャによるキャプチャの対象とすることを提案していました。これについて、R1では全部で7つのオプションが提示されています
- 契約述語はキャプチャをトリガーできる
assume
属性における同様の議論では、そのようなキャプチャをill-formedにするために言語の複雑化を正当化するには実際のコードで問題が起きる可能性が低い(エッジケースである)として、キャプチャをトリガーすることを維持した- 契約注釈にも同じことが言える
- 契約述語はキャプチャをトリガーしない
- P2932R2で提案されている
- 単にキャプチャをトリガーしない、とするだけだと契約注釈で間違った変数を使用してしまう可能性がある(ローカル変数と同名のグローバル変数を暗黙的に使ってしまう)
- 契約述語がキャプチャをトリガーする場合ill-formed
- オプション2の問題をカバーしたもの
- 言語が複雑化し、ユーザーにとって自明ではないかもしれない
assume
属性と矛盾する
- 契約述語がキャプチャをトリガーする場合警告する
- 契約注釈からキャプチャをトリガーするコードは常に疑わしいコードであり、警告するならill-formed(オプション3)の方が望ましい
- 契約述語内で他の方法でodr-usedされないエンティティをodr-usedすることはill-formed
- クラステンプレートのインスタンス化にも影響を与える
- デフォルトキャプチャを使用したラムダ式で契約注釈指定を許可しない
- ユーザにとってあまりに多くの価値を奪うものであり、思い切りが良すぎる
- ラムダ式で契約注釈の使用を許可しない
- 6と同様
この提案では、この中で実行可能な選択肢は1か3のどちらかであるとしています。なお、現在のContracts MVP仕様としては2が採用されています(別の提案によるもの)。
P2894R1 Constant evaluation of Contracts
定数式においても契約チェックを有効化する提案。
以前の記事を参照
R0では、コンパイル時に契約チェックするかどうか(及び定数式で実行できない契約条件の扱いをどうするか)について、グローバルなスイッチによって一律的に制御するようなことを提案していましたが、翻訳単位によってその設定が異なる可能性があることを指摘されました。それによって再検討が行われ、このリビジョンでは結局実行時と同様に、全ての契約注釈のセマンティクスは実装によって定義され、注釈ごと、その評価ごとに変化しうる、というモデルを採用することになりました。
以前はコンパイル時にセマンティクスを区別する必要はない、としていましたが、実装が定数評価中にそのセマンティクスを選択する以上3種類のセマンティクスが定数評価中にどのように動作するかを指定する必要があります。
この提案での検討対象はR0と同様に次の場合のみです
- 契約条件式はコア定数式ではない
- 契約条件式はコア定数式だが、
false
に評価された(契約が破られた)true
にもfalse
にも評価されない場合は全て、コア定数式ではない
まず1の場合、契約注釈を持つ関数が定数式で呼ばれるまではその契約条件式の定数実行可能性を気にしないことはR0と同様です。定数実行できない契約注釈を持つ関数が定数式で呼ばれてしまった時が問題になります。
その場合、R0では実装定義(コンパイラオプション等で指定)としていました。このリビジョンでは、契約違反が起きたものとして扱うことを提案しています。すなわち、コンパイル時に呼び出すことのできない事前・事後条件(及びアサーション)はコンパイル時には決して満たされることはないと言うことであり、それは契約違反となります。契約違反時の動作は契約注釈のセマンティクスによって指定されます。
2の場合とはつまり契約違反が起きたと言うことであり、その動作はセマンティクスごとに指定され、次のようになります
- ignore, observe : 診断を発行(エラーにならない)
- enforce : 診断を発行しill-formed(エラーになる)
そして、定数式における契約注釈のセマンティクスは契約注釈及びその評価ごとに実装定義(オプション等によって指定)となります。
また、定数初期化されうる変数の初期化式などの定数式で評価されるかどうかが決定的でない文脈においての契約注釈の評価については、上記のようなセマンティクス適用以前に、その契約注釈を含む式が定数評価可能かを契約注釈を無視してテストして、定数評価可能ならば再度契約セマンティクスを有効化した上で初期化式の評価を行うようにすることを提案しています。
P2900R2 Contracts for C++
↓
P2900R3 Contracts for C++
以前の記事を参照
R2での変更は
- 構文としてnatural syntaxを採用
- P2961R2を採択
default
関数に対する事前/事後条件の指定はill-formed- P2932R2を採択
このリビジョンでの変更は
delete
関数に対する事前/事後条件の指定はill-formed- ラムダ式に対する事前/事後条件の指定を許可
- 契約注釈は暗黙のラムダキャプチャをトリガーしない
- P2932R2を採択
std::contracts::invoke_default_contract_violation_handler()
(デフォルトの違反ハンドラを呼び出す関数)を追加- 契約条件式から参照されるローカルエンティティは暗黙的に
const
とする- P3071R1を採択
- 事後条件における戻り値名のセマンティクスを明確化
- P3007R0を採択し、戻り値名は暗黙的に
const
とする
- P3007R0を採択し、戻り値名は暗黙的に
- Overviewセクションを追加
- Recursive contract violationsセクションを追加
などです。
P2909R3 Fix formatting of code units as integers (Dude, where's my char?)
↓
P2909R4 Fix formatting of code units as integers (Dude, where's my char?)
std::format()
のchar
を整数値としてフォーマットする際の挙動を改善する提案。
以前の記事を参照
- P2909R0 Dude, where's my char? - WG21月次提案文書を眺める(2023年08月)
- P2909R2 Fix formatting of code units as integers (Dude, where's my char?) - WG21月次提案文書を眺める(2023年09月)
R3での変更は
- LEWGでの投票結果を追加
このリビジョンでの変更は
- 機能テストマクロ
__cpp_lib_format
を__cpp_lib_format_uchar
に置き換え wchar_t
への対応を改善するために文言を調整
などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2918R2 Runtime format strings II
std::format()
の実行時フォーマット文字列のためのAPIを追加する提案。
以前の記事を参照
このリビジョンでの変更は
- 機能テストマクロ
__cpp_lib_format
をバンプするようにした runtime-format-string
に説明専用メンバstr
を追加runtime-format-string
にコンストラクタを追加- この提案で追加される関数には
noexcept
を付加する runtime-format-string
を固定化
などです。
この提案は、2023年11月のKona会議で採択され、C++26WDにマージされています。
P2932R2 A Principled Approach to Open Design Questions for Contracts
契約機能に関する未解決の問題についての設計原則に基づく解決策の提案。
以前の記事を参照
- P2932R0 A Principled Approach to Open Design Questions for Contracts - WG21月次提案文書を眺める(2023年09月)
- P2932R1 A Principled Approach to Open Design Questions for Contracts - WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は
- セクションをいくつか追加
- 定数式の処理セクション、observeセマンティクスを持つ契約注釈の実行時以外の評価についてのセクションを明確化
- 提案1.Bをトリビアルな特殊メンバ関数に適用するように修正し、1.Cを追加
- natural syntaxを使用するように書き換え
などです。
提案1.Cはトリビアルでないものも含めてdefault
で定義された関数に対して契約注釈を行えるのかどうかについてのもので、次のようなものです
default
関数が、その最初の宣言で事前条件/事後条件を持つ場合、ill-formed
これは、default
とはインターフェースなのか実装なのか、それに関して契約注釈はどうあるべきかなどについての議論を行うために、C++26に対してはとりあえず禁止しておくことを意図したものです。C++26 Contracts仕様にはこれが採用されています。
P2933R1 std::simd
overloads for <bit>
header
<bit>
にあるビット演算を行う関数について、std::simd
向けのオーバーロードを追加する提案。
以前の記事を参照
このリビジョンでの変更は、文言も含めた全体のテキストの修正などです。
P2935R4 An Attribute-Like Syntax for Contracts
C++契約プログラミングのための構文として属性構文を推奨する提案。
以前の記事を参照
- P2935R0 An Attribute-Like Syntax for Contracts - WG21月次提案文書を眺める(2023年08月)
- P2935R2 An Attribute-Like Syntax for Contracts - WG21月次提案文書を眺める(2023年09月)
- P2935R3 An Attribute-Like Syntax for Contracts - WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は
[[assert : expr]]
を式にした- 事後条件における戻り値命名の代替案の追加
などです。
2023年11月のKona会議において、C++契約プログラミングのための構文としてはこちらではなくP2961R2のnatural syntaxを採用することが決定されました。
P2952R1 auto& operator=(X&&) = default
default
な特殊メンバ関数の戻り値型をauto&
で宣言できるようにする提案。
以前の記事を参照
このリビジョンでの変更は、void
戻り値型の指定とそのトリビアル性(この提案では許可しない)についての議論を追加したことです。
P2961R2 A natural syntax for Contracts
契約プログラミング機能のための構文の提案。
以前の記事を参照
- P2961R0 A natural syntax for Contracts - WG21月次提案文書を眺める(2023年09月)
- P2961R1 A natural syntax for Contracts - WG21月次提案文書を眺める(2023年10月)
このリビジョンでの変更は
- アサートのキーワードとして
contract_assert
を採用 assert
が契約におけるアサートのキーワードとしてふさわしくない理由を追記- 実装経験について追記
- SG22での議論をもとに、Cでの実現可能性について追記
などです。
この提案は2023年11月のKona会議でC++26の契約プログラミング機能のための構文として採用されました。
P2968R1 Make std::ignore
a first-class object
↓
P2968R2 Make std::ignore
a first-class object
std::ignore
を戻り値破棄のために合法的に使用できるようにする提案。
以前の記事を参照
R1での変更は
- ビットフィールドについて言及し、それが
std::ignore
の代入にとって有効な右辺オペランドではないことを説明 - 右辺オペランドとしてnon-volatileビットフィールドがサポートされるべきかの質問を追加
- 既存の主要な実装の分析を含むフィードバック提案を組み込み
- volatileビットフィールドによる副作用を防ぐために、ビットフィールドを右辺オペランドとして指定しない
operator=(auto&&)
を使用してコードとして仕様を推奨
このリビジョンでの変更は
- 個別のヘッダにしないことを決定
std::ignore
の代入演算子のシグネチャとしてoperator=(auto const &) const noexcept
を使用するauto&& -> const auto&
に変更し、左辺値参照修飾を削除
などです。
std::ignore
の代入演算子はあらゆる値を受けることができ、ほとんどの場合に元の値の読み取り(すなわちコピー)は発生しません。しかし、その例外がビットフィールドであり、ビットフィールドを渡そうとすると対応する整数型の一時オブジェクトを生成して渡す形になり、ビットフィールドの値へのアクセスが発生します。これが特に問題となるのはそのビットフィールドがvolatile
である場合で、volatile
の場合はその値へのアクセスを消し去ることができず、std::ignore
の代入演算子が何もしないという効果を達成できなくなります。
std::ignore
の代入演算子の規定としてどんな値でも受け取り何もしないと言う風に指定する代わりに、コードとして代入演算子のシグネチャを指定し引数型を制限することでこの問題は解決できます。その際に、引数型をauto&&
(ビットフィールド禁止)にするのかcosnt auto&
(volatile
ビットフィールドを受けられない)にするのかによってビットフィールドを許可するか、あるいは非volatile
ビットフィールドを許可するかが分岐します。
このリビジョンでは、cosnt auto&
にすることでstd::ignore
ではビットフィールドを許可するもののvolatile
ビットフィールドはサポートしないことにしています。
この提案はすでにLEWGのレビューを終えてLWGに転送されています。
P2969R0 Contract annotations are potentially-throwing
contract_assert
式に対するnoexcept
演算子の振る舞いについての解決策を探る提案。
C++26 Contractsのセマンティクスとして、特に例外に関する部分についてSG21では次のことが合意されています
- 契約条件式の評価に伴って例外がスローされる場合は契約違反として扱われ、関数の例外仕様とは無関係に違反ハンドラを呼び出す
- 違反ハンドラからの例外送出は、通常の例外と同じ扱いとなる
- スタック巻き戻しが発生し、巻き戻しが
noexcept
関数呼び出しに及んだ場合はstd::terminate()
によってプログラムは終了する
- スタック巻き戻しが発生し、巻き戻しが
- 契約注釈がチェックされているかどうかによって、
noexcept
演算子の結果や契約注釈が付加されている関数の型が変化することはない - 事前条件・事後条件・アサーションは全て、述語または違反ハンドラからの例外送出に関して同じように動作する
これによって、チェックされると常に例外を送出する、Well-definedな動作をもつWell-formedなC++プログラムが存在し得ます
#include <contracts> using namespace std::contracts; void handle_contract_violation(const contract_violation&) { throw 666; } int main() { contract_assert(false); // チェックされると必ず例外を送出する }
しかもこのことは、契約違反ハンドラがnoexcept
であることがわかっている場合にのみコンパイル時にわかります(違反ハンドラの置換は一般的にリンク時に行われるため、コンパイル時には分からないでしょう)。従って、違反ハンドラがどの様にカスタマイズされているか(あるいはされていないか)によらず、ユーザーから見た契約注釈は常に例外を投げうるものとして写ります。
現在のC++にはプログラムのコンパイル時のセマンティクスが特定の式が例外送出するかどうかに依存する場合があります。それは、noexcept
演算子の結果を決定する時、最初の宣言がdefault
である特殊メンバ関数の例外仕様を決定する場合、の2つの場合です。
2023年11月のKona会議において、クラスの特殊メンバ関数の最初の宣言がdefault
である場合、契約注釈を付加できないことが決定されました。しかし、それでもなお、この2つの場合のそれぞれについて契約注釈の有無によって結果が変化しうる場合が存在し、現在のMVP仕様ではその状況について何も指定していません。
1つは、契約注釈そのものにnoexcept
演算子を適用した場合で、これはcontract_assert()
でのみ起こります。
noexcept(contract_assert(false)); // これはtrueになる?falseになる?
2つめは、クラスの特殊メンバ関数の例外仕様が推定される場合で、通常この場合はその関数が例外を投げうるものを含んでいなければnoexcept(true)
と推定されます。現在その様な場所に直接契約注釈を付加することはできませんが、間接的に現れる可能性があります
struct B { int i = (contract_assert(false), 42); }; struct S : B { // これらのコンストラクタのnoexcept性はどうなる? S() = default; S(S&&) = default; };
この様なコンテキストは現在この2つだけのはずですが、将来の機能(例えば、noexcept(auto)
)を考慮するとさらに増加する可能性があります。
この提案は、C++26に契約機能を導入する前にこれらの仕様の空白を埋めるために可能な解決策を探るものです。
この提案で上げられている解決策は次の7つです
- 契約注釈を例外を送出しうるものとして扱う
- 上記どちらも、
noexcept(false)
となる - ゼロオーバーヘッド原則に反する(契約注釈の追加によりムーブコンストラクタの例外仕様が変化するなど)。これは契約機能の採用の阻害要因となりうる
- 上記どちらも、
- 契約注釈を例外を送出しないものとして扱う
- 1と2の両方の状況を許可する
- 謝って送出された例外が推定された
noexcept(true)
例外仕様を回避できる様にする- 契約注釈は言語内で例外を投げないものとして扱われるが、違反ハンドラからスローされた例外のみ
noexcept(true)
な関数のスタック巻き戻しを行うことが許可される - 呼び出しが例外を投げないことを前提とする処理でこれが起こると、結局プログラムの実行は安全ではなくなる
- 例外仕様のメンタルモデルが複雑化し言語内に矛盾が生じ、仕様と実装が複雑化する
- 契約注釈は言語内で例外を投げないものとして扱われるが、違反ハンドラからスローされた例外のみ
- これらの場合が現れない様にする
- 次の3つの方法が考えられる
- 仕様や実装が複雑になり、ユーザーにより多くの苦労を強いることになるが、上記問題を回避し全ての場合にゼロオーバーヘッド原則を満たす
- ガイドラインと診断に頼る
- ユーザーにその様なコードを書かないほうがいいと警告するならば、単にill-formedとしたほうがいい
- 違反ハンドラからの例外送出サポートを禁止する
- 違反ハンドラからの例外送出を使用するのは実際には非常に難しいため、これを削除し例外を使用しない方法で同等の契約違反後の処理継続を可能にする方法を模索する
- それを決定するとこの提案で挙げられている問題は全て解決されるが、後から違反ハンドラからの例外送出を許可するのは困難になる
- 現時点では例外に代わる同等のメカニズムは存在していない
この提案では、それぞれの解決策による影響や実現可能性について考察していますが、どれかを推しているわけではありません。ただし、3,4の案は実現可能ではないと評されており、1,2,6の案は問題があり、7の案も困難が伴うとして、一番ポジティブな評価を受けているのは5(の2,3)の案です。
この提案でどの様な決定がなされたとしても事前・事後条件における違反ハンドラからの例外送出について同様の問題がある様に見えますが、それはすでに合意済みのことです。契約注釈の存在は例外仕様等のコンパイル時セマンティクスに影響を与えず、Lakos Ruleに基づいて契約注釈がなされている限り(無条件noexcept
指定と契約注釈の両立は誤っている)それは問題になりません。例えば、あるクラスのムーブコンストラクタがnoexcept
となる場合、そのムーブコンストラクタは広い契約を持ちいかなる事前・事後条件も持たないはずで、そのクラスのメンバのムーブコンストラクタそれぞれについても同様の仮定が成立するはずです。この過程が成り立っていない場合、そのムーブコンストラクタはnoexcept(false)
とするのが適切であり、その場合にのみ契約注釈によって事前・事後条件をチェックすることができます。
P2977R0 Module commands database format
ツール間で同じモジュールを生成するために必要となるコンパイルのための情報をファイルにまとめておく提案。
ビルドシステムのようなC++プロジェクトのビルドを管理するツールは、それをコンパイルしたコンパイラとは異なるコンパイラを使用するプロジェクトにおいてもモジュールを管理しなければなりません。しかし、一般的にビルド済みモジュールはコンパイラ間や同じコンパイラのバージョン間、あるいはモジュールを分析する必要のあるツール(静的解析ツールなど)等それぞれの間で互換性がありません。これらのツールはメインのビルドの設定に対応する形で、それぞれ独自の形式によってモジュール(のインターフェース)をビルドできる必要があり、メインのビルドと(形式等は除いて)同等のコンパイル済みモジュールを生成するために必要なフラグなどを知る必要があります。
この提案は、そのような情報をファイルに保存してツール間でやり取りすることを目的として、どのような情報が必要かやその保存の方法などを特定しようとするものです。
メインビルドと同等のコンパイル済みモジュールを作成するためには、ツールは少なくとも次の情報を知っている必要があります
- モジュールインターフェースのソース
- 生成されるモジュールのモジュール名
- そのモジュールが使用される場所を特定するために必要
- 必要なモジュールの名前(依存モジュール名)
- モジュールの依存関係を解決するために必要
- 必要なモジュールを提供するソースコード
- ソース内でのモジュールの可視性
- モジュール実装単位/実装パーティションのように、プライベートなモジュールが存在する
- そのようなモジュールに属するシンボルは外部からアクセスできない場合があり、より的確な診断のためにモジュール名を使用できる
- ソースを処理するビルド中に使用されるローカルプリプロセッサ引数
- メインビルドの成果物に対応するものを生成するために使用する必要がある
- ツールは、メインビルドに使用されるコンパイラのフラグを自身の利用のために変換する必要がある可能性がある
- コンパイルのための作業ディレクトリ
- 相対パスの解釈を一致させるために必要
これらの情報をビルドツリー内で表現する方法としては次の3つが挙げられています
- スタンドアロン
- 全ての情報を何らかのファイルに保存する
- (おそらくソースファイルごとに)別々のファイルとして存在している
- この利点は、情報をビルドだけでなくインストールにも使用できる点
- コンパイルコマンドデータベースとの相互参照
- Compile Commands Databaseと手元の情報とを組み合わせて使用する
- 重複を減らすことができるが、必要な情報を全て取得するには2つのデータベースを手動でマージするツールが必要になる
- この欠点は、あるソースが異なるフラグでビルドグラフ上に複数回現れうる点
- コンパイルコマンドデータベースとの共有
このようなモジュールコンパイルデータベースは、一般的にビルド中に作成される必要があります。なぜなら、モジュール名はビルドが完了するまでわからないからです。しかし、上記コンパイルコマンドデータベースがビルドの一部が完了するまで存在しない生成されるソースのコンパイルを参照することができ、新しい問題というわけではありません。
メインビルドに関わらない他のツールがこれらの情報を簡易に取得するために、ビルドシステムはモジュールコンパイルデータベースをよく知られた場所(おそらく、pkgconfigなどのようなものがある場所)にあるファイルにまとめる仕組みを提供する必要があります。これによって、他のツールが関連ファイルを探索する手間が軽減され、ファイル全体にわたって情報が一貫していることが保証されます。
この提案はこのような要件を列挙したもののようで、まだ何かを提案するには至っていないようです。
P2980R1 A motivation, scope, and plan for a quantities and units library
物理量と単位を扱うライブラリ機能の導入について説明する提案。
以前の記事を参照
このリビジョンでの変更は
- ガーディアン紙の華氏の取り扱いに関する問題について追加
- ScopeとPlan for standardizationを更新
- タイトルからPhysicalを取り除いた
などです。
P2981R1 Improving our safety with a physical quantities and units library
↑の物理量と単位を扱うライブラリ機能について、コンパイル時の安全性に関する側面を解説する文書。
以前の記事を参照
このリビジョンでの変更は
- ガーディアン紙の華氏の取り扱いに関する問題について追加
- 燃料消費の例を拡張
- いくつかの参考リンクを追加
- 型を保持する型特製についてLack of safe numeric typesで説明
- Non-negative quantitiesを書き直し
- Limitations of systems of quantitiesセクションを追加
- Temperaturesセクションを追加
などです。
P2982R1 std::quantity
as a numeric type
↑の物理量と単位を扱うライブラリ機能について、数値と計算の側面に関する設計の説明をする文書。
以前の記事を参照
このリビジョンでの変更は
- 燃料消費の例を拡張
- Dimension is not enough to describe a quantityセクションを拡張
- Lack of convertibility from fundamental typesセクションを追加
- Terms and definitionsセクションにmp-unitsの用語集へのリンクを追加
- Equivalenceセクションのサンプルコードを修正
などです。
P2984R1 Reconsider Redeclaring static constexpr Data Members
static constexpr
メンバ変数のクラス外定義の非推奨の扱いを検討する提案。
以前の記事を参照
このリビジョンでの変更は
- コンパイラの警告についての状況を追加
- 2023年11月のKona会議におけるレビュー結果について追加
- conclusionセクションを追加
などです。
EWGのレビューにおいては、static constexpr
メンバ変数のクラス外定義を削除することが好まれた様でしたが、一方で現在十分に非推奨動作であることが警告されていない状況でいきなり削除してしまう事は好まれなかった様です。そのため、C++26に対してはこの点に関して変更を加えず、コンパイラベンダにはこの問題についての警告をよりユーザーに見える様にすることを推奨する、という方向性が支持されました。
P2996R1 Reflection for C++26
値ベースの静的リフレクションの提案。
以前の記事を参照
このリビジョンでの変更は
- 全てのサンプルにCompiler Explorerでの動作例リンクを付加
synth_struct
をdefine_class
に再指定- いくつかのメタ関数を関数テンプレートの代わりに関数として再指定
- エラー処理メカニズムと例外の優先設定に関するセクションを追加
- チケットカウンタとバリエーションの例を追加
entity_ref
とpointer_to_member
をvalue_of
で表現する様に置き換え
などです。
静的リフレクションにおけるエラーとは例えば、std::meta::template_of(^int)
のような間違ったコード(template_of(^T)
は型T
のテンプレートの鏡像を取得する。int
はテンプレートの特殊化ではないのでエラー)が何を返すか?という問題です。
この候補としては現時点で次のものが考えられます
- 静的リフレクション過程のエラーは定数式ではない(コンパイルエラー)
- 無効値(エラーであること、およびソースの場所とその他有用な情報)を保持する鏡像を返す
- P1240の推奨アプローチ
std::expected<std::meta::info, E>
を返す。E
はソースの場所とその他有用な情報を提供するE
を例外としてスローする- 定数式で例外を許可する必要がある。おそらく、定数式中でキャッチされない例外のみコンパイルエラーとなる様にする
2つ目の方法の欠点は、メタ関数が範囲を返す場合(template_arguments_of(^int)
の様な場合)に何を返すかという点です。この場合に単一の無効な鏡像値を返すと正常なものが帰る場合との一貫性がなくなり、使いづらくなります。かといって、空の範囲を返してしまうとエラー情報が失われてしまいます。結局、何を返したとしても、expected
もしくは例外のアプローチの方がより一貫性があり簡単なエラー処理を提供します。
例外にはいくつかの懸念がありますが、ここでの文脈は定数式であるため、実行時における例外の問題点はここでは問題になりません。その上で次のようなよく使用されると思われる様な例を考慮すると
template <typename T> requires (template_of(^T) == ^std::optional) void foo();
template_of(^T)
がexpected<info, E>
を返す場合、foo<int>
は置換失敗expected<info, E>
とinfo
は等値比較可能であり、結果はfalse
となり制約を満たさなくなる
template_of(^T)
が例外を送出する場合、foo<int>
から送出された例外がキャッチされない場合はコンパイルエラー- これは置換失敗ではなく、制約が定数式ではなくなることによるエラー
- 置換失敗にする場合、まず制約で
T
がテンプレートであることを確認するか、制約が定数式であることを要求する言語の規定を変更する
これらのことを考慮し、例外の懸念を考慮しても、この提案では静的リフレクションにおけるエラー伝搬にはexpected
よりも例外の方がユーザーフレンドリーであるとしています。
P2999R1 Sender Algorithm Customization
↓
P2999R2 Sender Algorithm Customization
↓
P2999R3 Sender Algorithm Customization
P2300のsender
アルゴリズムがカスタマイズを見つける手段を修正する提案。
以前の記事を参照
R1での変更は、提案する文言を追加したこと、比較テーブルを追加したことなどです。
このリビジョンでの変更は
- 早期のカスタマイズと後からのカスタマイズの例を追加
- 早期のカスタマイズを残す理由について追記
connect
時のドメイン計算を修正sender
の要件に完了scheduler
が全てドメインを共有するという要件を追加transform_sender
は必要に応じて再帰することを明確化- 不要になっていた説明専用の
make-transformer-fn
を削除
などです。
P3006R0 Launder less
バイト配列上に構築した別の型のオブジェクトへのポインタをより直感的に取得できる様にする提案。
バイト配列を確保して、その配列の要素型とは異なる型のオブジェクトをその配列上に構築する場合、そのオブジェクトへの正しいアクセス方法は非常に限定されています。
// Tのオブジェクトを配置するバイト配列 alignas(T) std::byte storage[sizeof(T)]; // Tのオブジェクト構築、戻り値のポインタをそのアクセスに使用する T* ptr1 = ::new (&storage) T(); // ok // storageのアドレスから直接Tのオブジェクトへのアドレスを得る T* ptr2 = reinterpret_cast<T*>(&storage); // UB T* ptr3 = std::launder(reinterpret_cast<T*>(&storage)); // ok
この場合、配置new
によってstorage
上に構築されているオブジェクトへのアクセスを行えるのはptr1
とptr3
のみであり、storage
のアドレスからreinterpret_cast<T*>
しただけのptr2
からのアクセスは未定義動作となります。
これはポインタとその領域で生存期間内にあるオブジェクトとが結びつかないためで、配置new
の戻り値を使用しない場合はptr3
のようにstd::launder
によってその領域上で生存期間内にあるオブジェクトへのポインタを取得しなければなりません。
とは言えこのことはかなり意味論的なことで、多くのコンパイラはptr2
の様にstd::launder
を使用しない場合でもstd::launder
を使用する場合と同等のコードを出力する様です。
この提案は、その様な既存の慣行を標準化し、このようなユーザーの期待に沿わないUBを取り除こうとするものです。
これによるメリットは、現在UBを回避するために配置new
の戻り値を保存している様なコード(例えば、Boost.Optionalなど)において、その様なポインタを保存しなくてもよくなることでストレージサイズを削減でき、なおかつstd::launder
というよく分からないものを使用せずとも直感的なコードによってUBを回避して意図した動作を実現できる点です。
P3007R0 Return object semantics in postconditions
事後条件の契約注釈で戻り値を参照する場合の、その戻り値のセマンティクスに関する提案。
事後条件注釈では、その関数の戻り値を使用するために戻り値の名前を指定してそれを参照することができます。
int f() post (r: r > 0); // 戻り値は正の値
現在のMVP仕様では、まだこの戻り値に関するセマンティクスが正確に指定されていません。
C++20時点の仕様及びそれを受け継いだMVP仕様においては、「事後条件では、その関数のglvalueもしくはprvalueの結果オブジェクトを表す識別子を導入できる」とだけ言及されていて、その値カテゴリは何か、それは参照なのか、その型は何か、アドレスを取れるのか、変更可能なのか、などについての規定はありません。
この提案は、事後条件の戻り値のセマンティクスについての現在の不明な点について考察し、そのセマンティクスを決定しようとするものです。ここで提案されていることは次のような事です
- 事後条件における戻り値を表す変数名は、本物の戻り値オブジェクトを参照する左辺値である、とする
- これは構造化束縛によって導入される名前のセマンティクスからの借用
- その値カテゴリは左辺値(lvalue)
- 言語参照(
T&
)ではないが、戻り値を参照している - 従って、事後条件から戻り値を参照する場合にはコピーもムーブも行われず、RVOを妨げない
- 戻り値名
r
に対するdecltype(r)
の結果は、関数の戻り値型 - 戻り値型がtrivially copyableである場合、戻り値名のアドレスと実際の戻り値のアドレスは異なる可能性がある
- これは、trivially copyableオブジェクトをレジスタに配置して返す挙動を変化させない(ABI破壊を回避する)ため
- その場合、戻り値名は戻り値を保持する一時オブジェクトを参照している
- 呼び出し側で戻り値を受ける変数が
const
である場合、関数の戻り値型がconst
でなければ、事後条件における戻り値の変更は未定義動作とならない、とする- 変数に対する
const
は初期化が完了するまで有効ではなく、事後条件は戻り値を受ける変数の初期化よりも前に呼び出される
- 変数に対する
この提案では、事後条件における戻り値名が暗黙const
であるかは著者の間で合意できなかったことから提案していません。それには利点と欠点がありますがどちらを採用するべきかは明確ではないため、その方向性の決定は委員会に委ねています。
P3016R1 Resolve inconsistencies in begin/end
for valarray
and braced initializer lists
std::valarray
と初期化子リストに対してstd::begin
とstd::cbegin
を呼んだ場合の他のコンテナ等との一貫しない振る舞いを修正する提案。
以前の記事を参照
このリビジョンでの変更は
- CWG Issue 2825. Range-based for statement using a braced-init-listを分離し、この提案はライブラリの変更のみとなった
.data(), .empty()
メンバ関数についての議論を追加initializer_list
のメンバbegin
を使用しているところを.data()
を使う様に置き換える文言を追加
などです。
P3019R1 Vocabulary Types for Composite Class Design
↓
P3019R2 Vocabulary Types for Composite Class Design
↓
P3019R3 Vocabulary Types for Composite Class Design
動的メモリ領域に構築されたオブジェクトを扱うためのクラス型の提案。
以前の記事を参照
R1での変更は
- 機能テストマクロの追加
std::indirect
にstd::format
サポートを追加- 使用前後の比較サンプルをまとめたAppendix Bを追加
- 型が値を持つことを事前条件として追加
constexpr
サポートを追加std::polymorphic
のQoIとしてsmall buffer optimizationを許可- アロケータサポートのために文言を追加
- 不完全型のサポートを有効化
pointer
入れ子型はallocator_traits::pointer
を使用する様に変更std::uses_allocator
特殊化を削除std::indirect
コンストラクタのinplace_t
を削除sizeof
エラーを削除
R2での変更は
std::indirect
比較演算子の戻り値型がauto
であることについての議論を追加emplace()
の議論をappendixに追加- allocator awarenessサポートのために文言調整
このリビジョンでの変更は
- コンストラクタに
explicit
を追加 indirect(U&& u, Us&&... us)
コンストラクタオーバーロードと制約を追加polymorphic(allocator_arg_t, const Allocator& alloc)
コンストラクタオーバーロードを追加std::variant
との類似/相違点についての議論を追加- 破壊的変更とそうではない変更の表を追加
- 不足している比較演算子を追加し、それらが条件付き
noexcept
であることを確認 std::indirect
の推論補助を修正- 複雑な例における
std::indirect
の間違った使用例を修正 swap()
のnoexcept
に関する文言を修正std::indirect
の比較演算子の制約に関する文言についての問題を解決- コピーコンストラクタは
allocator_traits::select_on_container_copy_construction
を使用する様にした - 自己
swap
と自己代入が問題とならないことを確認 std::optional
特殊化を削除- erroneousの使用をundefined behaviourで置き換え
- コピー代入における強い例外保証を追加
- コンストラクタにおいて、
T
のuses-allocator構築を行う様に指定 - 文言の見直し
などです。
P3022R1 A Boring Thread Attributes Interface
std::thread/std::jthread
に対してスタックサイズとスレッド名を実行開始前に設定できるようにするAPIの提案。
以前の記事を参照
このリビジョンでの変更は
- P2019R4の変更に追随
- 文言と例を追加
- Conclusionセクションを追加
などです。
この提案の方向性はLEWGでの指示が得られなかったため、追及は停止されています。
P3023R1 C++ Should Be C++
C++標準化委員会の目標・見通しについて問い直す文章。
以前の記事を参照
R0が主張をリストアップしたものだったのに対して、こちらはそれを文章にまとめた形になっている完成版です。
P3024R0 Interface Directions for std::simd
C++26に向けて提案中のstd::simd
のインターフェースやその設計動機などについて紹介するスライド。
P3025R0 SG14: Low Latency/Games/Embedded/Financial trading/Simulation virtual Minutes to 2023/09/12
SG14の2023年9月12日に行われたオンラインミーティングの議事録。
P3026R0 SG19: Machine Learning virtual Meeting Minutes to 2023/07/13
SG19の2023年7月13日に行われたオンラインミーティングの議事録。
P3027R0 UFCS is a breaking change, of the absolutely worst kind
P3021のUFCS(Unified function call syntax)提案に異議を唱える提案。
P3021については以前の記事を参照
P3021では、メンバ関数呼び出しを拡張する形でUFCSを有効化することを提案しており、メンバ関数呼び出し(x.f(a,b)
とx->f(a, b)
)を非メンバ関数の呼び出し(f(x, a, b)
とf(*x, a, b)
)にフォールバックすることでUFCSを可能にするものです。
P3021のUFCSは確かに既存のコードを壊しません(有効なコードがill-formedにならない)が、現在のメンバ関数呼び出しに関してユーザーが依存している保証を壊している、というのがこの提案の主張です。
その保証とは、メンバ関数呼び出しはADLとは無関係に行われるというものであり、別の言い方をするとメンバ関数呼び出しではADLは行われないという保証です。このため、確かに現在ある既存のコードが壊れることはありませんが、将来のコードは壊れる可能性があります。
例えばリファクタリングにおいて誰もが経験すると思われる、メンバ関数の名前を変更する場合を考えます。
struct Foo { // この関数名を変えたい void snap(); }; // この.snap()は例えばこのように呼び出されている template <class T> void do_snap(T&& f) { f.snap(); }
このFoo::snap()
の名前をslap()
に変更しようとする場合、これを宣言・定義しているファイルを編集し名前を変更してから使用されているところを修正していけば良いでしょう。修正を忘れたり、呼び出しを間違えればコンパイラがコンパイルエラーとして修正が完全ではないことを教えてくれます。これは静的型付け言語の基本中の基本振る舞いであり、コードベースが大きくなったとしてもそれは変化しません。
しかしP3021が有効化された場合そのような保証はもはや期待できず、snap()
をslap()
に変更してなにも修正しなかったとしても一切エラーが出ない可能性があります。なぜなら、ADLによってslap()
を探しに行き、たまたま呼び出せる候補を見つけてしまうかもしれないからです。P3021が導入される以前はメンバ関数呼び出しからADLが発動されることはなく、ADLによって呼び出せてしまうようなslap()
を定義していたとしても安全でした。しかし、P3021導入後はそのような関数がメンバ関数呼び出しからのADLによって呼び出されることを意図していたかどうかは分からなくなります(P3021以前の保証の上に立っているのか、P3021の機能の上に立っているのかが分からなくなるため)。
これはまた、メンバ関数を削除する場合や、関数の引数型を変えるなどのリファクタリングにおいても同様です。
本来であればメンバ関数呼び出しではそのようなADLの複雑さを考えなくても良いはずで、P2855のようにそれを有効に利用しようとする向きもあります。しかし、P3021の機能が導入されるとそのような保証はなくなり、メンバ関数呼び出しは常に意図しない関数呼び出しによってバグを静かに埋め込んでしまう可能性を抱えることになります。
意図的かどうかはともかく、現在の多くのC++ユーザーはメンバ関数呼び出しを使用することでクラスのメンバ関数のみが呼び出され、ADLの複雑さについて頭を悩ませることを回避しています。メンバ関数はクラスという単位でのカプセル化によって、そのアクセス範囲及び呼び出される方法はかなり明確です。
メンバ関数呼び出し構文がそのようなカプセルの外側に及ぶようにするというのは、その単純さと分かりやすさを壊しています。それはユーザーへのサービスではなく、ユーザーに対して破滅的な不利益を与えるものです。
このような理由によりこの提案はP3021のUFCSに反対し、UFCSが必要ならば専用の構文を導入して行うべきであり、既存の関数呼び出し構文を拡張する形でそれを行えば以前にはその複雑さが無かった場所に新しい複雑さを導入してしまい、UFCSによる利点を複雑さの増大による欠点が上回るとしています。
P3028R0 An Overview of Syntax Choices for Contracts
2つの契約構文候補を比較する提案。
C++26契約プログラミング機能に向けて議論が進んでおり、残す大きな問題は構文の決定のみとなっています。現在契約構文としてはC++20の契約機能由来の属性様構文(P2935)と新しい文脈依存キーワードによる自然な構文(P2961R2)の2つが候補として残っています。
P2695で示されたロードマップに従って、2023年11月のKona会議ではこのどちらの構文を採用するのかを決定する予定です。
この提案はその議論のために、2つの構文候補を比較することでそれぞれの特性を明らかにしようとするものです。
この提案では次の2つの観点から候補を比較しています
- 提案されている全ての構文候補を、契約のある機能についてそれぞれ対応する構文で記述したものを横に並べて比較
- P2885で挙げられている原則とともに、各構文候補がその原則をどの様に満たすのか(あるいは満たさないのか)を比較
事前条件構文の比較
// P2935 void f() [[ pre : true ]]; // P2961 void f() pre( true );
事後条件構文の比較
// P2935 int f() [[ post r : true ]]; int f() [[ post (r) : true ]]; // P2935R4の代替提案 int f() [[ post : r : true ]]; // P2961 int f() post( r : true );
アサーション構文の比較
// P2935 void f() { [[ assert : true ]]; } // P2961 void f() { contract_assert( true ); }
かかる文字数の比較
P2935 | P2961 | |
---|---|---|
事前条件 | 8 | 5 |
事後条件 | 9〜10 | 6〜7 |
アサーション | 11 | 17 |
これ以外にも様々な観点からの比較が行われています。
2023年11月に行われたKona会議では、P2961の自然な構文をC++契約プログラミング機能のための構文として採用することで合意されました。
P3029R0 Better mdspan's CTAD
std::span
/std::mdspan
がコンパイル時定数によってインデックス指定を受ける場合のCTADを改善する提案。
たとえば、mdspan
でよく使用されることになると思われる配列ポインタとそれを参照する多次元インデックスの指定を受けるコンストラクタに対応する推論補助は次の様に定義されています
template<class ElementType, class... Integrals> requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) explicit mdspan(ElementType*, Integrals...) -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>;
このため、このコンストラクタ(CTAD)が使用される場合にはインデックスにコンパイル時定数を渡していてもmdspan
のエクステントはdextent
(実行時エクステント)が使用されます。
mdspan ms (p, 3, 4, 5); // mdspan<int, extents<size_t, dynamic_extent, dynamic_extent, dynamic_extent>> mdspan ms2(p, 3, integral_constant<size_t, 4>{}, 5); // 同上 mdspan ms3(p, integral_constant<size_t, 3>{}, 4, integral_constant<size_t, 5>{}); // 同上
後2つについてはコンパイル時定数を渡しているため、エクステントのその部分は静的になってほしいものがあります。現在これを叶えるためには、ユーザーは次の様に記述する必要があります
mdspan ms2(p, extents<size_t, dynamic_extent, 4, dynamic_extent>(3, 5)); // mdspan<int, extents<size_t, dynamic_extent, 4, dynamic_extent>> mdspan ms3(p, extents<size_t, 3, dynamic_extent, 5>(4)); // mdspan<int, extents<size_t, 3, dynamic_extent, 5>>
最初の例の後ろ2つが自動的にこれと同等になることが望ましいでしょう。また、std::span
にも同様の問題があります。
この提案は、std::mdspan
及びstd::span
の推論補助を修正して、動的インデックス指定がコンパイル時定数(std::integral_constant
のような型の値)によって指定されている場合にそれを静的な指定としてエクステントに反映する様にしようとするものです。
これによる利点は次の様なものが挙げられています
- 動的・静的エクステントを同等な形式によって指定できるため、エクステント型の反映が直感的になる
- 現在、動的エクステントは数値で直接コンストラクタに指定できるのに対して、静的エクステントは
std::extents<I, idx...>{...}
の様に指定する必要がある
- 現在、動的エクステントは数値で直接コンストラクタに指定できるのに対して、静的エクステントは
- 正しい数の引数を渡すために
dynamic_extents
の数を計算する必要がなくなり、エラーが起こりにくくなる - P2781の
std::constexpr_v
を使用すると、エクステントが混在するmdspan
をmdspan(c_<3>, 4, c_<5>)
の様に記述できる様になる。
この様なことはstd::submdspan
(C++26に導入済)では既に行われており、その仕組みを再利用することで実装可能です。
まず次の様な検出ユーティリティを用意して(integral-constant-like
はstd::submdspan
とともに導入済)
// std::integral_constantと同等の型を検出する template<class T> concept integral-constant-like = // exposition only is_integral_v<decltype(T::value)> && !is_same_v<bool, remove_const_t<decltype(T::value)>> && convertible_to<T, decltype(T::value)> && equality_comparable_with<T, decltype(T::value)> && bool_constant<T() == T::value>::value && bool_constant<static_cast<decltype(T::value)>(T()) == T::value>::value; template<class T> constexpr size_t maybe-static-ext = dynamic_extent; // exposition only template<integral-constant-like T> constexpr size_t maybe-static-ext<T> = static_cast<size_t>(T::value);
これを用いてstd::mdspan
及びstd::span
の既存の動的エクステント指定に対応する推論補助を修正します
// 変更前 template<class It, class EndOrSize> span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>>; // 変更後 template<class It, class EndOrSize> span(It, EndOrSize) -> span<remove_reference_t<iter_reference_t<It>>, maybe-static-ext<EndOrSize>>; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // 変更前 template<class ElementType, class... Integrals> requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) explicit mdspan(ElementType*, Integrals...) -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>; // 変更後 template<class ElementType, class... Integrals> requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0) explicit mdspan(ElementType*, Integrals...) -> mdspan<ElementType, dextents<size_t, maybe-static-ext<Integrals>...>; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
P3031R0 Resolve CWG2561: conversion function for lambda with explicit object parameter
ジェネリックなthis
パラメータを持つラムダ式の関数ポインタへの変換の規定が曖昧なのを解決する提案。
C++23のDeducing thisはクラスのメンバ関数でthis
パラメータを明示的に書くことができる機能です(この引数の事を明示的オブジェクトパラメータと呼びます)。これはラムダ式においても使用することができますが、ラムダ式の場合はそのクロージャ型名を知ることができないので、通常this auto
のように書かれます。
また、ラムダ式はキャプチャしていない場合にのみ関数呼び出し演算子のシグネチャと互換性のある関数ポインタへ変換することができます。
このとき、明示的オブジェクトパラメータを持つラムダ式が対応する関数ポインタへ変換可能であるかについて実装間で挙動に差があります。
int main() { using T1 = decltype([](int x) { return x + 1; }); // ok、ラムダ式のクロージャ型 int(*fp1)(int) = +T1{}; // ok、関数ポインタへの変換 using T2 = decltype([](this auto, int x) { return x + 1; }); // ok、ラムダ式のクロージャ型 int(*fp2)(int) = +T2{}; // Clangはng、MSVCはok }
1つ目の例は通常のラムダ式から関数ポインタへ変換する例です。これはC++11以来のもので今回特に問題はありません。
2つ目の例がこの提案の主要な問題であり、ジェネリックな明示的オブジェクトパラメータを持つラムダ式が対応する関数ポインタへ変換できるかどうかが、現時点でこの機能を実装しているClangとMSVCの間で異なっているようです。
また、ラムダの明示的オブジェクトパラメータがジェネリックではなかったとしてもClangは拒否するようで、どうやら規格ではこの場合に生成されるクロージャ型のメンバがどうなるかについて曖昧なようです。
struct Any { Any(auto) { puts("called"); } }; int main() { auto a1 = [](int x) { return x+1; }; auto a2 = [](this Any self, int x) { return x+1; }; // 明示的オブジェクトパラメータはジェネリックではない int(*fp)(int) = +a2; // Clangはng、MSVCはok }
このa1, a2
それぞれのクロージャ型は例えば次のようになります
// 型変換演算子で複雑な型を使用するためのエイリアス template<class T> using Just = T; // a1のクロージャ型の例 struct A1 { int operator()(int x) const { return x+1; } operator Just<int(*)(int)>() const { return +[](int x) { return A1()(x); }; } }; // MSVCにおけるa2のクロージャ型の例 struct A2_MSVC { int operator()(this Any self, int x) { return x+1; } operator Just<int(*)(int)>() const { return +[](int x) { return A2_MSVC()(x); }; } }; // Clangにおけるa2のクロージャ型の例 struct A2_Clang { int operator()(this Any self, int x) { return x+1; } operator Just<int(*)(Any, int)>() const { return &A2_Clang::operator(); } };
Clangにおいては明示的オブジェクトパラメータの部分の引数についても関数ポインタ型へ現れるようです。一方、MSVCは明示的オブジェクトパラメータは関数ポインタに現れません。
MSVCの挙動は、従来の暗黙的オブジェクトパラメータを持つラムダを明示的オブジェクトパラメータを持つものにそのままリファクタリングでき(その逆も可能)たり、自身の型を関与させない形で再帰ラムダを定義できたりと、よりユーザーフレンドリーであると思われます。
// Error on Clang, OK on MSVC auto fib = [](this int (*fib)(int), int x) { return x < 2 ? x : fib(x-1) + fib(x-2); }; int i = fib(5);
この例は、Clangの場合はthis
パラメータの型に自身の型が再帰的に現れるのを回避することができませんが、MSVCはこのように関数ポインタによってその再帰を断ち切ることができます。これは再帰ラムダを非ジェネリックに定義できるため、コンパイル時間で有利になるかもしれません。
ラムダ式の関数ポインタへの変換演算子に関して、MSVCはラムダ式における明示的オブジェクトパラメータをかなり特別扱いしており、その引数は常にそのラムダ式自身と同等とみなせると強く仮定しています。ラムダ式が関数ポインタへ変換可能であるのはキャプチャしていない場合のみなので、これは実際にはあまり問題にならないかもしれません。
一方で、this auto
を用いずにテンプレート構文によって明示的オブジェクトパラメータを記述するとMSVCでもClangと同様なクロージャ型を生成するようです。
auto a = [](this auto) {}; // MSVCは非ジェネリックとして扱う auto b = []<class T>(this T) {}; // ジェネリックラムダ auto pa = +a; // OK on MSVC auto pb = +b; // error on MSVC void (*qa)() = a; // OK on MSVC void (*qb)() = b; // error on MSVC
この非一貫性は非自明ではあります。
この問題はCWG Issue 2561で捕捉され、当初はClangのアプローチを標準化する方向性でした。この提案はそれに対してMSVCのアプローチの方を推すものでしたが、それには文言についてさらなる検討が必要になるということで、明示的オブジェクトパラメータを持つ関数の関数ポインタへの変換をとりあえず禁止しておくことを提案するものです(このR0が出る前に6つのリビジョンがあった様子)。
この提案には、明示的オブジェクトパラメータを持つラムダ式の関数ポインタへの変換を禁止する、Clangのアプローチを採用、MSVCのアプローチを採用、の3つのオプションが含まれており、EWGは1つ目のアプローチを採用したようです。ただし、これはMSVCのアプローチを将来的に採用することを妨げるものではありません。
- CWG Issue 2561. Conversion to function pointer for lambda with explicit object parameter
- メンバ関数の新しい書き方、あるいは Deducing this - Zenn
- P3031 進行状況
P3033R0 Should we import function bodies to get the better optimizations?
モジュールのインターフェースにある関数定義をそのモジュールをインポートした翻訳単位にインポートしないようにする提案。
Clangの最適化においては、あるモジュールからインポートされた関数について、その関数の定義をインライン化するような最適化をリンク前に行っているようです。
// a.cppm export module a; export int a() { return 43; } // use.cpp import a; int use() { return a(); }
たとえば、最適化を有効にするとuse.cpp
のuse()
はint use() { return 43; }
であるかのようにコンパイルされます。
これはゼローバーヘッド原則に則っており、一見合理的であるように見えます。しかし、use.cpp
をコンパイルする時にオプティマイザはモジュール内のa()
に対しても作用してしまうため、プロジェクトの規模が大きくなるとコンパイル時間に跳ね返ってきます。
とはいえそれでも、この問題は単に実装の問題であり規格が口を出す話ではないように思えます。しかし、実際にはABI依存関係と潜在的なODR違反に関連しています。
例えば上記コード群が次のようなコンパイル結果を生成していた場合
a.o // モジュールaのオブジェクトファイル a.pcm // モジュールaのBMI use.o // use.cppのオブジェクトファイル libuse.so // use.cppを含む共有ライブラリ
この時にモジュールa
内のa()
を44
を返すように変更して再コンパイルした場合、再コンパイルが発生して再生成されるのはどのファイルでしょうか?これには2つのオプションがあります
rebuild a.o rebuild a.pcm rebuild use.o link libuse.so
もしくは
rebuild a.o rebuild a.pcm link libuse.so
この2つの違いはuse.cpp
が再コンパイルされるかどうかだけです。モジュールの位置づけを考えた場合は再コンパイルされないのが正しい振る舞いにも思えますが、その場合インライン化されているa()
の定義の変更が反映されません。 再コンパイルする場合は実装の一貫性は保たれますが、コンパイル時間が増大します。あるいは、最適化を有効にしている場合にのみABI依存関係(現在一般的ではない)に基づいて再コンパイルを行うべきでしょうか?
この提案ではこの問題への対処として、モジュール本文内の非inline
関数本体を変更する場合、対応するモジュールインターフェースのBMIを変更するべきではない、とすることを提案するものです。
すなわち、ユーザーがモジュールインターフェースユニット(の本文)内の非インライン関数の本体のみを変更したプロジェクトを再コンパイルする場合、再コンパイルされるのは変更されたモジュールインターフェースのみであり(そのBMIすらも再コンパイルするべきではなく)、他のすべてのコンパイルは行われるべきではありません。ただし、リンクを除きます。
提案では、これによりユーザーエクスペリエンスが向上するはずとしています。
ビルドシステムのレベルでは、ビルドシステムが再コンパイルが必要かを決定する依存関係はモジュールのソースではなくモジュールのBMIに依存するように実装することでこれが実現できます。そして、コンパイラはBMIにはモジュールからエクスポートされているインターフェースのみを保存しておき、その定義を保存しないようにする必要があります。GCC/MSVCは現在そのようにしていますが、Clangは2フェーズコンパイルモデルを実行する都合上そのようになっていないようです。
実行時のパフォーマンスについても、ヘッダファイルベースのライブラリをモジュールに移行することを考えた場合、ヘッダファイル内の関数はほぼインライン関数であるためこの提案の制約に接触せず、パフォーマンスの低下が発生する場合は限定されるとしています。また、LTOを使用することで翻訳単位を跨いだ定義のインライン化のような最適化が可能となるため、問題とされている最適化が全く利用できなくなるわけではありません。
P3034R0 Module Declarations Shouldn't be Macros
名前付きモジュールのモジュール宣言において、モジュール名のマクロ展開を禁止する提案。
モジュールのソースファイル形式は他のものと区別されておらず、あるファイルがモジュールソースであるかは、そのファイルの先頭にモジュール宣言があるかどうかによって決まります。モジュール宣言およびグローバルモジュールフラグメントの宣言はプリプロセッサによって導入することができませんが、モジュール名はマクロの展開によって指定することができます。
例えば、次の様なコードはC++20時点で有効です
// version.h #ifndef VERSION_H #define VERSION_H #define VERSION libv5 #endif // lib.cppm module; #include "version.h" export module VERSION;
あるソースファイルがモジュールファイルであり、かつそのモジュール名が何であるかを知ることは、ソースの依存関係を知るために必要な作業です。従来のヘッダインクルードであれば、その依存関係を知らなくてもビルドを行うことができますが、モジュールの場合はビルドにあたってその依存関係を把握しソースのビルド順を決定する必要があります。これを行うのはコンパイラではなくビルドシステムの仕事であるため、ビルドシステムはソースファイルを読み込みそれがモジュールであるか、モジュールの場合はその名前は何かを読み取る必要があるかもしれません(これを行わなくてもいい方法がいくつか考案されていますが、まだ標準化等されてはいません)。
モジュール宣言はプリプロセッサによって導入されないものの、モジュール名はマクロの展開を完了させた上で読み取らなければなりません。そのためには、上記例のようにグローバルモジュールフラグメント内のインクルードやマクロ定義を読み込んだ上でマクロの展開を行わなければなりません。その作業は実装も処理も簡単なものとは言えず、ビルドシステムの実装および処理時間にかなりの負担になります。
この様な理由から、この提案はモジュール名もマクロによって導入できない様にする提案です。
その目的はモジュールファイルのパースを簡単にすることでビルドシステムがモジュール名パースを実装しやすくすることにあります。また、ビルドの前にモジュールの依存関係解決フェーズを行う場合に、パース処理が単純化されることで依存関係解決フェーズの遅延時間を短くすることもできます。
ただし、この変更はC++20への破壊的変更になります。提案では、モジュールの実装はまだ出揃っておらず使用例も稀であるため、影響は最小限である、としています。
この提案はSG15でもEWGでもほぼ反対なく支持されたようで、EWGではこの提案をC++20へのDRとするつもりの様です。
P3037R0 constexpr std::shared_ptr
std::shared_ptr
を定数式でも使える様にする提案。
C++20で定数式における動的メモリ確保が可能になり、C++23でstd::unique_ptr
がconstexpr
対応され定数式で使用できる様になりました。
スマートポインタは実行時と同様に定数式においてもメモリ管理を自動化することができます。しかし、std::shared_ptr
はその実装に必要な言語機能の一部が定数式で使用可能ではなかったためすぐにconstexpr
対応することができませんでした。
C++23におけるP2738R1(void*
からの正しいポインタキャストの許可)とP2448R2(定数式で実行不可能なものは評価されるまではエラーにならない)の採択によりその障害は取り除かれており、この提案はそれを受けてC++26に向けてstd::shared_ptr
をconstexpr
対応しようとするものです。
筆者の方はlibstdc++のstd::shared_ptr
実装をベースとして実装を試みており、アトミック操作の使用を回避の必要性やstd::make_shared()
などの行う1回のメモリ確保による初期化の問題などを報告していますが、いずれも回避は可能であり実装可能であるとしています。
また、この提案ではさらに、C++23ではconstexpr
で実装できなかったため外されていたstd::unique_ptr
の比較演算子に対してもconstexpr
を付加することも提案しています。
- P2738R0 constexpr cast from void*: towards constexpr type-erasure - WG21月次提案文書を眺める(2023年01月)
- C++23 constexpr関数が定数実行できない場合でも適格とする - cpprefjp
- P3037 進行状況
P3038R0 Concrete suggestions for initial Profiles
既存のC++コードの一部により強力な保証を付加するためのプロファイルについての提案。
この提案は、P2687で提案されていたアイデアについて、より具体的な最初の機能について説明するものです。
プロファイルはC++コード上でユーザーによって指定されるもので、スコープもしくはモジュールに対して付加することができます。
// モジュール宣言にmemory_safetyプロファイルを適用 export module DataType.Array [[enforce(memory_safety)]]; // 名前空間宣言にプロファイルを適用 namespace N [[enforce(p)]] { ... }
[[enforce(p)]]
はプロファイルp
をそのスコープに対して適用するもので、そのスコープの内側にあるコードに対してプロファイルp
の保証が強制されます。モジュールの場合の適用範囲は、そのモジュール本文の全体です。
// モジュールMに対してプロファイルPを適用 import M [[enable(P)]]; // モジュールoldでtype_safetyプロファイルを無効化 import old [[suppress(type_safety)]];
プロファイルは既存コードに付加して保証を強化するものであり、[[enable(P)]]
によって特にプロファイルを使用していないモジュールのインポート時にプロファイルを適用することができます。また、プロファイルはスコープに対して指定されある程度広い領域でその保証が強制されるため、[[suppress(P)]]
によって部分的にプロファイルを無効化することもできます。
想定されるプロファイルにはいくつかの種類が考えられますが、この提案では実装負担の軽減のために最初の小さいものとしてtype_safety
プロファイルに焦点を当てています。与えられる保証は例えば
- 変数初期化の強制
[[uninitilize]]
とマークされない変数には初期化が必要
- ポインタの利用の制限
- ポインタは単一要素を指すか、
nullptr
であるかのどちらか- ポインタによる範囲のランダムアクセス禁止、その用途には
span
やvector
を使用する
- ポインタによる範囲のランダムアクセス禁止、その用途には
owner
とマークされていない限り、ポインタは所有権を持たないowner
はポインタの先のオブジェクトを破棄する責任を負うowner
以外のポインタに対してnew/delete
できない
nullptr
チェックなしのポインタアクセスの禁止
- ポインタは単一要素を指すか、
- ダングリングポインタ(参照)の抑止
- ポインタ(参照)はオブジェクトを指すか、
nullptr
のどちらか owner
ではないポインタはdelete
できない- 生存期間が不明なポインタを外側のスコープに漏出できない
return
できるポインタを制限する
- ポインタ(参照)はオブジェクトを指すか、
- ポインタ(参照)の無効化の防止
- 非
const
参照によってコンテナを取得する関数では参照の無効化が発生する可能性があり、const
参照によってコンテナを取得する関数では参照の無効化が発生しないと仮定 - 非
const
参照によってコンテナを取得するがコンテナを変更しない関数では[[not_invalidating]]
アノテーションによってそれを表明する- 間違った
[[not_invalidating]]
の利用は検出できるはずで、エラーにする
- 間違った
- 非
提案文書より、例
void f1() { int n; // error [[uninitialized]] int m; // ok } void f2(int* p1, owner<int*> p2) { delete p1; // error、ownerでは無いポインタをdeleteいている delete p2; // p2はdeleteしないとエラー } void f3(int* p1, owner<int*> p2) { p1=p2; // OK、p1はownerではないが、p2と同じオブジェクトを指す p2=p1; // error、p2は上書きされる前にdeleteされなければならない } int* glob = nullptr; void f4(int* p) { glob = p; // error、不明な生存期間のポインタを保存しようとしている } int glob2 = 0; int* f5(int* p) { int x = 4; return &x; // error: ローカルオブジェクトへのポインタを返そうとしている return p; // OK: pは関数呼び出し時に有効であり、無効化されていない return new int{7}; // error, ownerポインタを非ownerで返そうとしている return &glob2; // OK 静的オブジェクトへのポインタ throw p; // error: pを*pのスコープ外に漏出しうる } void f6(vector<int>& vi) { vi.push_back(9); // 要素の再配置が発生しうる } void f7() { vector<int> vi { 1,2 }; auto p = vi.begin(); // viの最初の要素を指すイテレータ f6(vi); // 参照を無効化しうる関数呼び出し *p = 7; // error、参照が無効化されている可能性がある }
提案では、このtype_safety
プロファイルに加えて、vector
等の範囲に対するアクセスの境界チェックを行う実行時検査を伴うプロファイルであるranges
プロファイルや、組み込み数値演算の安全性向上(オーバーフロー防止、縮小変換・符号変換の禁止など)のためのプロファイルであるarithmetic
プロファルなどを初期のプロファイルの候補として挙げています。
このようなプロファイルに基づく保証の提供はC++ Core Guidelineおよびそのチェッカー実装とガインドラインサポートライブラリの経験から来ています。それはあくまで静的解析としてC++コンパイルとは別でチェックされることでしたが、プロファイルとしてその保証をC++のコードに対して取り込むことで、既存のC++コードの上に被せる形でC++コードの安全性を高めることができ、プロファイルの指定は小さななスコープから始めることができます。
この提案のプロファイルとその静的な検査については、コアガイドラインチェッカーにて現在利用できるものであり、実装可能であることが確かめられています。また、この提案による安全性の静的検査は、コンパイラに強力なフロー解析などを強いるものではなく、危険を招く可能性のある操作を制限することで抑止するとともに、コンパイラの静的解析にいくつかの仮定を与えることで解析を補助する事を目指す物です。
P3039R0 Automatically Generate operator->
<=>
演算子の様な書き換えによってoperator->
を導出する提案。
この提案では、->
と->*
演算子をオーバーロード解決時に書き換えて実行することでこの2つの演算子を自動で導出できる様にすることを提案しています。それぞれ次の様になります
lhs->rhs
を(*lhs).rhs
に書き換えて実行lhs->*rhs
を(*lhs).*rhs
に書き換えて実行
ライブラリソリューション(Boost.Operatorsのような)でこれと同じことを行おうとする場合、*lhs
がprvalueを返す場合(例えばプロクシイテレータなど)に一時オブジェクトの寿命が->
の定義内で尽きてしまうことによって未定義動作が発生する問題が回避できません。しかし、言語機能による演算子の書き換えはその様な問題を回避することができます(その場でインラインに置換される形になるので、->
の呼び出しコンテキストと書き換え後の*lhs
の生存コンテキストは一致する)。
また、比較演算子の場合は逆順の演算子や細かいコーナーケースを処理するためにその書き換えルールが複雑になっていますが、->
と->*
はどちらも逆順を考慮する必要がなく、->
はクラス内でのみ定義でき右辺のオペランドはオーバーロード解決とは無関係となるため、書き換えに伴う仕様はかなりシンプルになります。
どちらの演算子でも、まずは->
/->*
として定義されたもの(delete
含む)を優先して選択し、それが見つからずoperator*
が利用可能である場合にのみ書き換えた候補を使用します。->
を定義したいクラス側でdefault
宣言しておく必要はなく、書き換えによって導出されたくない場合はdelete
宣言をしておくことで書き換えを抑止できます。
これによるメリットは、主にイテレータ定義時の->
に関する記述をほぼ完全に削除することができる点です。
提案では、<=>
にならってこの提案が採択された場合に既存の->
定義を削除するオプションについて検討されており、そこではC++20時点の標準ライブラリで->
を持つクラスにおける定義のされ方を調査しています。それによれば、スマートポインタやstd::optional
、コンテナのイテレータ型や一部のRangeアダプタのイテレータ型など、多数のクラス型において->
定義を削除することができることが示されています。
ただし、std::iterator_traits
のpointer
メンバ型の定義や、std::to_address
とstd::pointer_traits
などその動作について->
演算子の存在に依存している部分があるライブラリ機能について、この提案の影響を回避する様にしなければなりません。それについてはいくつか方法が提示されているものの未解決です。
P3040R0 C++ Standard Library Ready Issues to be moved in Kona, Nov. 2023
11月に行われたKona会議でWDに適用されたライブラリに対するIssue報告の一覧
- 2392. "character type" is used but not defined
- 3203.
span
element access invalidation - 3305.
any_cast<void>
- 3431.
<=>
for containers should requirethree_way_comparable<T>
instead of<=>
- 3749.
common_iterator
should handle integer-class difference types - 3892. Incorrect formatting of nested ranges and tuples
- 3897.
inout_ptr
will not update raw pointer to 0 - 3946. The definition of const_iterator_t should be reworked
- 3809. Is
std::subtract_with_carry_engine<uint16_t>
supposed to work? - 3947. Unexpected constraints on
adjacent_transform_view::base()
- 3948.
possibly-const-range
andas-const-pointer
should benoexcept
- 3949.
std::atomic<bool>
's trivial destructor dropped in C++17 spec wording - 3951. §[expected.object.swap]: Using
value()
instead ofhas_value()
- 3953.
iter_move
forcommon_iterator
andcounted_iterator
should returndecltype(auto)
- 3957. §[container.alloc.reqmts] The value category of
v
should be claimed - 3965. Incorrect example in [format.string.escaped] p3 for formatting of combining characters
- 3970. §[mdspan.syn] Missing definition of
full_extent_t
andfull_extent
- 3973. Monadic operations should be ADL-proof
- 3974.
mdspan::operator[]
should not copy OtherIndexTypes - 3987. Including
<flat_foo>
doesn't providestd::begin/end
- 3990. Program-defined specializations of std::tuple and std::variant can't be properly supported
- 4001.
iota_view
should provideempty
P3041R0 Transitioning from "#include" World to Modules
ヘッダファイルによるライブラリをモジュールベース変換する際の実装戦略についての報告書。
標準ライブラリモジュールstd
と標準ヘッダファイルは同時にインポート/インクルードしたとしてもODR違反等を起こさず一貫して使用可能であることが規定されています。
#include <vector> import std; int main() { // vectorおよびそのメンバ関数実体は曖昧にならない std::vector<int> vee { 1, 2, 3, 4, 5 }; return vee.size(); }
これは、通常のユーザーが定義できる名前付きモジュールでは得られない保証です。
ヘッダインクルードによるエンティティはグローバルモジュールに属しており、モジュールのエンティティは名前付きモジュールという翻訳単位に属しています。この2つのものは例え同じ名前で定義されていたとしても異なるものとして扱われるため、上記の様なコードをユーザー定義ライブラリでやると意図通りになるか曖昧になるかは実装次第となります。しかし標準ライブラリモジュールとヘッダファイルに関しては、これが確実に動作する(ヘッダファイルとstd
モジュールとの対応する名前は同じ1つのエンティティを参照する)ことが規定され、要求されています。
これは、標準ヘッダと標準モジュールの両方を適用する必要がある現状においても両方を自然に同居させるための要求ですが、もしこの様な保証をユーザー定義の名前付きモジュールに対しても与えることができれば、ヘッダファイルとモジュールを同時に提供するライブラリの実装が可能になり、ヘッダからモジュールへの移行を促進することができます。
また、上記の様な標準ライブラリの保証を実現する実装戦略は、グローバルモジュール(ヘッダファイル)のエンティティに対してstd
モジュールのエンティティを対応づけるような形になる様ですが、これは名前付きモジュールのいくつかの利点を犠牲にしています。
この報告書は、ヘッダとモジュールを同時に提供しながら名前付きモジュールの利点を余すところなく享受し、なおかつそれを任意のC++ライブラリで利用可能にする実装戦略について説明するものです。
この戦略は、ビルド定義とコンパイラが連携してBMIマッピングと#include
変換を組み合わせることで、現在のstd
モジュールの保証を実現するものです。標準ライブラリヘッダに関しては、ビルドは次の様に行われます
- 標準ライブラリヘッダのインクルードをヘッダユニットのインポートへ変換
- 全ての標準ヘッダユニットに対して、
std
モジュールのBMIを使用する様にコンパイラへ指示する - 標準マクロを強制的にインクルードする
マクロに関してはこの方法では導入できないため、別途(コマンドライン等から)インクルードする必要があります。この文書では、C互換ではない標準ヘッダが提供する必要のあるマクロをまとめたヘッダファイルを用意しそれをインクルードする事を推奨しています。
この実装戦略は標準モジュールに対してのものですが、より一般のC++ライブラリに対しても適用可能です。ただし、そのためには次のようなものが必要です
- あるヘッダが名前付きモジュール(または別のヘッダ)に含まれていることを記述する機能
- ヘッダのインクルードをヘッダユニットのインポートへ変換する機能
- 2のヘッダユニットのBMIを包含モジュールのBMIへマッピングする機能
- ヘッダファイルで導入されるはずのマクロを強制的にインクルードする機能
現在のところこれらの機能のいずれも非標準ライブラリに対しては提供されていません。
P3042R0 Vocabulary Types for Composite Class Design
P3019の紹介スライド。
std::indirect
とstd::polymorphic
のモチベーションや設計要求などについて丁寧に説明されています。おそらく、提案を見るよりも分かりやすそうです。
P3043R0 Slides: Using variable template template without meta programming
変数テンプレートテンプレートの動機付けについて説明する文書。
lldにあるコードを簡略したものを整理することを例にとって、変数テンプレートテンプレート(変数テンプレートを受け取るテンプレートパラメータ)の必要性を説明しています。ただし、これ自体は何かを提案しているわけではありません。
これを可能とする提案としては例えばP2989があります。
P3046R0 Core Language Working Group "ready" Issues for the November, 2023 meeting
11月に行われたKona会議でWDに適用されたコア言語に対するIssue報告の一覧。
- 1038. Overload resolution of
&x.static_func
- 1698. Files ending in
\
- 2054. Missing description of class SFINAE
- 2102. Constructor checking in new-expression
- 2252. Enumeration list-initialization from the same type
- 2504. Inheriting constructors from virtual base classes
- 2531. Static data members redeclared as constexpr
- 2556. Unusable
promise::return_void
- 2570. Clarify constexpr for defaulted functions
- 2591. Implicit change of active union member for anonymous union in union
- 2595. "More constrained" for eligible special member functions
- 2600. Type dependency of placeholder types
- 2628. Implicit deduction guides should propagate constraints
- 2672. Lambda body SFINAE is still required, contrary to intent and note
- 2725. Overload resolution for non-call of class member access
- 2733. Applying
[[maybe_unused]]
to a label - 2747. Cannot depend on an already-deleted splice
- 2749. Treatment of "pointer to void" for relational comparisons
- 2753. Storage reuse for string literal objects and backing arrays
- 2754. Using *this in explicit object member functions that are coroutines
- 2755. Incorrect wording applied by P2738R1
- 2758. What is "access and ambiguity control"?
- 2759.
[[no_unique_address]]
and common initial sequence - 2760. Defaulted constructor that is an immediate function
- 2761. Implicitly invoking the deleted destructor of an anonymous union member
- 2762. Type of implicit object parameter
- 2763. Ignorability of
[[noreturn]]
during constant evaluation - 2764. Use of placeholders affecting name mangling
- 2768. Assignment to enumeration variable with a braced-init-list
- 2772. Missing Annex C entry for linkage effects of linkage-specification
- 2780.
reinterpret_cast
to reference to function types - 2783. Handling of deduction guides in global-module-fragment
- 2785. Type-dependence of requires-expression
- 2789. Overload resolution with implicit and explicit object member functions
- 2791. Unclear phrasing about "returning to the caller"
- 2792. Clean up specification of noexcept operator
- 2793. Block-scope declaration conflicting with parameter name
- 2795. Overlapping empty subobjects with different cv-qualification
- 2796. Function pointer conversions for relational operators
- 2798. Manifestly constant evaluation of the
static_assert
message - 2801. Reference binding with reference-related types
- 2806. Make a type-requirement a type-only context
- 2807. Destructors declared
consteval
- 2823. Implicit undefined behavior when dereferencing pointers
P3050R0 Optimize linalg::conjugated for noncomplex value types
std::linalg::conjugated()
を非複素数型に対してアクセサの変更をしないようにする提案。
std::linalg::conjugated()
は複素数配列を参照するmdspan
の各要素を、その複素共役となるように変換する関数です。ただし、戻り値もmdspan
で返され、変換はmdspan
のアクセサポリシーを変更することで行われます。従って実際の要素は変更されず、mdspan
からの要素参照時に引き当てられた要素に対して複素共役への変換を行うことで配列全体の変換を行います。
namespace std::linalg { // conjugated()の宣言例 template<class ElementType, class Extents, class Layout, class Accessor> constexpr auto conjugated(mdspan<ElementType, Extents, Layout, Accessor> a); }
std::linalg::conjugated()
の現在の動作は次のようになっています
- 入力
mdspan<T, E, L, A>
のアクセサ型A
がconjugated_accessor<NestedAccessor>
(NestedAccessor
は任意の他のアクセサ型)である場合、mdspan<NestedAccessor::element_type, E, L, NestedAccessor>
を戻り値型として入力a
の領域とレイアウトをそのまま渡して返す - それ以外の場合、
mdspan<T, E, L, conjugated_accessor<A>>
を戻り値型として入力a
の領域とレイアウトをそのまま渡して返す- 複素共役を行うアクセサポリシー
conjugated_accessor
で元のアクセサをラップする
- 複素共役を行うアクセサポリシー
conjugated_accessor<A>
はアクセサポリシーA
をラップして、A
で定義されたアクセス結果に対して複素共役変換を適用して返すアクセサポリシー型です。
conjugated_accessor<A>
による変換は、conj-if-needed()
という説明専用の関数によって行われ、conj-if-needed(c)
はc
に対するADLによって非メンバconj()
が使用可能であればそれを使用して複素共役を取得し、それが見つからない場合はc
をそのまま返します。これによって、c
およびmdspan
の要素型が複素数型ではない場合はこの変換は最適化によってスキップされることが期待できます。
しかし、その呼び出し階層を削除することができたとしても、conjugated_accessor
型の存在を削除することはできません。
mdspan
を扱う多くのユーザーは関数等でmdspan
を受け取る場合デフォルトのポリシーを使用して型を記述し、特にアクセサ型を変更する形で記述されることは稀だと思われます(すなわち、要素型T
に対してdefault_accessor<T>
が専ら使用されるはず)。
そのようなユーザーは<linalg>
の主機能であるBLASラッパを使用しないとしても、std::linalg::conjugated()
などのユーティリティは使用することになるでしょう。そして、自身の持つmdspan
をstd::linalg::conjugated()
に通すと、その要素型がなんであれアクセサポリシーが変更されたmdspan
が得られ、デフォルトのアクセサを使用したmdspan
を受け取るように定義された関数に対してそれを渡すとコンパイルエラーに遭遇するでしょう。
std::linalg::conjugated()
は複素数要素に対して作用するためこれは回避不可能なものであるといえるかもしれません。しかし、BLASそのものやMatlab等では、転置と共役転置(随伴)の操作は同じものとして統合されており、<linalg>
でもconjugate_transposed()
が用意されている他、conjugated(transposed(x))
のように書かれることもあるでしょう。これらの関数に対する入力はその要素型が浮動小数点数型か複素数型かを意識せずに渡されるはずで、この場合に非複素数要素型のmdspan
に対してアクセサ型の変更が行われることは驚きを伴う可能性があります。
これに対応するにはアクセサポリシー型をジェネリックにしなければならず、それはコンパイル時間の増大を招くとともに、デフォルトアクセサを仮定する最適化を行えなくなることを意味します。
LWGにおけるP1673のレビュー中にこの問題が指摘され、そのままでも致命的な問題ではなかったためP1673はそのままレビューされC++26 WDにマージされました。この提案は、改めてこの問題を解決するために提出されました。
この提案による変更は、std::linalg::conjugated()
がアクセサポリシーをconjugated_accessor
に変更しようとする場合(共役の共役とならない場合)にその要素型が複素数型ではないならば入力のmdspan
をそのまま返すようにします。これによって、次の2点の変更は観測可能となります
std::linalg::conjugated()
の戻り値型は必ずしもconjugated_accessor<A>
ではなくなる- 非複素数型の要素型の
mdspan
に対して、戻り値型のmdspan
はconst element_type
を持たなくなる
これは、conjugated()
の呼び出しは常にconst element_type
を持つわけではないことや、結果を他の関数に渡しているコードの呼び出しが壊れるわけではないことなどから許容されるとしています。
P3051R0 Structured Response Files
ツールが他のツールにコマンドラインオプションをファイルで引き渡す方法についての提案。
現在、いくつかのコンパイラはそのオプションをファイルにまとめて指定する方法を提供しています。それはよく似た方法で行われていますが、コンパイラ間で互換性はなく、相互運用が可能なものではありません。例えばファイルを渡すオプション名が異なり、ファイル形式もバラバラです。
そのような方法を標準化することで、ツールが他のツールへ(例えばビルドシステムからコンパイラへ)そのコマンドラインオプションを渡すことが容易になり、ツール間の相互運用性が向上します。また、そのような一貫した方法/フォーマットはツールに対する一貫した共通オプションのようなものを定義するための下地にもなります。
この提案は、コマンドラインオプションをまとめたファイルのフォーマットとそれを受け渡す方法について提案するものです。
提案ではファイルの形式としてJSONファイルとすることを提案しています。
そして、そのファイルにツールのオプションを記録する方法として、引数とオプションの2つのスタイルを提案しています。引数はコマンドラインオプション文字列をそのまま記録するもので、オプションは実際のコマンドラインオプションに対応するより概念的な指定となるものです。
提案より、それぞれの表現例
// 引数の例 { "arguments": [ "-fPIC", "-O0", "-fno-inline", "-Wall", "-Werror", "-g", "-I\"util/include\"", "-c" ] } // オプションの例 { "options": [ "fPIC", { "O": "0" }, "fno-inline", { "W": [ "all", "error" ] }, "g", { "I": [ "util/include" ] }, "c" ] }
引数のスタイルは既存のコマンドラインオプション構文に直接対応しており移行しやすいものですが、ツール依存になります。オプションは既存のコマンドラインオプション構文をより抽象化したもので、ツール間のオプション構文の差異を吸収できる可能性があります。また、これら2つのスタイルは1つのファイル内に同居することができます。
それぞれの利点/欠点
- 引数
- オプション
そして、このファイルを指定するコマンドラインオプションとしてstd-rsp
を提案しています。
tool --std-rsp=file tool -std-rsp:file
実際のファイル全体は例えば次のようになります
{ "$schema": "https://raw.githubusercontent.com/cplusplus/ecosystem-is/release/schema/std_rsp-1.0.0.json", "version": "1", "arguments": ["-fPIC", "-O0", "-fno-inline", "-Wall", "-Werror", "-g", "-I\"util/include\"", "-c" ] }
提案では、オプションスタイルの場合の各オプション名について、実際のコマンドライン引数名に対応させるか、より抽象的な名前にするかについて未解決としています(例えば、W, o, I
とwarning, output, include
)。これにも利点欠点があるため、どちらを選択するかやこの提案でそれを追求するかについてはSG15の決定に委ねています。
P3052R0 view_interface::at()
view_interface
にat()
メンバ関数を追加する提案。
C++26でP2821が採択されたことでstd::span
でもインデックスアクセスにat()
が使用できる様になり、既存の標準コンテナ等とのインターフェースの一貫性が向上しています。これにより、標準にある2つのview
型(span
とstring_view
)でat()
が使用できる様になったため、これをより汎用的なview
型でも一貫させることの根拠が生まれました。
残りのview
型とは<ranges>
の各種view
型(subrange
やRangeアダプタのview
型)のことで、これらの型はその共通インターフェースをview_interface
というCRTPベースクラスを継承することで提供しています。
この提案は、インデックスアクセスの安全性とインターフェースの一貫性を向上させるために、view_interface
にat()
メンバ関数を追加しようとするものです。
namespace std::ranges { template<class D> requires is_class_v<D> && same_as<D, remove_cv_t<D>> class view_interface { ... public: ... // 現在の添字演算子オーバーロード template<random_access_range R = D> constexpr decltype(auto) operator[](range_difference_t<R> n) { return ranges::begin(derived())[n]; } template<random_access_range R = const D> constexpr decltype(auto) operator[](range_difference_t<R> n) const { return ranges::begin(derived())[n]; } // 提案するat() template<random_access_range R = D> requires sized_range<R> constexpr decltype(auto) at(range_difference_t<R> n); template<random_access_range R = const D> requires sized_range<R> constexpr decltype(auto) at(range_difference_t<R> n) const; }; }
このat()
はコンテナ等のそれと同様に動作し、指定されたインデックスが範囲外参照となる場合にout_of_range
例外を送出するものです。view_interface
で提供されることで、<ranges>
のほぼ全てのview
型で使用可能になります。
P3053R0 2023-12 Library Evolution Polls
2023年12月に行われる予定のLEWGの全体投票の予定。
次の19個の提案が投票にかけられます
- P0876R14 fiber_context - fibers without scheduler
- P0447R26 Introduction of std::hive to the standard library
- P2542R7 views::concat
- P2642R5 Padded mdspan layouts
- P2663R5 Proposal to support interleaved complex values in std::simd
- P2810R2 is_debugger_present is_replaceable
- P2809R2 Trivial infinite loops are not Undefined Behavior
- P2845R5 Formatting of std::filesystem::path
- P2862R1 text_encoding::name() should never return null values
- P2867R1 Remove Deprecated strstreams From C++26
- P2869R3 Remove Deprecated shared_ptr Atomic Access APIs From C++26
- P2866R1 Remove Deprecated Volatile Features From C++26
- P2944R2 Comparisons for reference_wrapper
- P2933R1 Extend
header function with overloads for std::simd - P2976R0 Freestanding Library: algorithm, numeric, and random
- P2968R2 Make std::ignore a first-class object
- P2999R3 Sender Algorithm Customization
- P2267R1 Library Evolution Policies
- P2760R1 A Plan for C++26 Ranges
後ろの2つを除いて、残りのものはC++26に向けてLWGに転送するための投票です。
P3055R0 Relax wording to permit relocation optimizations in the STL
リロケーション操作による最適化を標準ライブラリのコンテナ等で許可するために、標準の規定を緩和する提案。
C++26に向けてリロケーション(relocation)操作を言語に導入する議論が進んでいます。リロケーションは意味的にはムーブ+破棄に相当し、ムーブした直後にムーブ元オブジェクトを破棄する操作をひとまとめにしたものです。中でも、トリビアルリロケーションはmemcpy
によってオブジェクト表現(ビット列)をコピーするだけで行うことができます。
リロケーション後の元のオブジェクトはコード上で使用不可になるという性質から、一部のムーブを伴う操作はリロケーションによって効率化できる可能性があります。特に、標準コンテナの操作やアルゴリズムに関わる操作などにおいて最適化を促進することが期待されています。
仮にリロケーション操作が言語に入った時に問題となるのは、それらコンテナやアルゴリズムの規定、特に計算量の規定がリロケーションではなくムーブを前提として指定されていることです。たとえば、std::vector::erase()
をリロケーションによって書き換えると次の様な実装になるでしょう
void erase(iterator it) { if constexpr (std::is_trivially_relocatable_v<value_type>) { std::destroy_at(std::to_address(it)); std::uninitialized_relocate(it + 1, end_, it); } else { std::ranges::move(it + 1, end_, it); // operator= std::destroy_at(std::to_address(end_ - 1)); } --end_; }
しかし、std::vector::erase()
の計算量の指定は、「要素型T
のデストラクタは消去された要素の数と等しい回数呼ばれ、T
の代入演算子は消去された要素の後にある要素の数と等しい回数呼ばれる」と規定されています。トリビアルリロケーションの場合、要素のムーブはそのオブジェクト表現のコピーのみで元オブジェクトの破棄は行われない(オブジェクトの配置場所が変わるだけでオブジェクトそのものは何ら変化しない)ため、std::vector::erase()
ではリロケーション操作が利用可能になったとしても標準の範囲内でそれを利用することができません。
このような規定がなされているものがコンテナの操作やアルゴリズムに関して存在しており、これがある限り言語にリロケーションが導入されても標準ライブラリはそれを活かすことができません。しかし、これを取り除いておけばリロケーションの到来と関係なく、標準ライブラリはトリビアルリロケーション可能であると現在わかっている型(std::deque<int>
など)についてそのような最適化を行うことができます。
この提案は、その様な過剰な制限を強いてしまっている現在の規定をリストアップし、それをトリビアルリロケーションをサポート可能なように緩和しようとするものです。
提案する変更は、全て現在の制限を若干緩めるものなので、既存の実装がこれを受けて何か変更する必要があるものではありません。たとえば、先ほどのstd::vector::erase()
の計算量の規定の場合、「元のvector
上で削除された一番先頭にある要素の後にある要素の数について線形」の様に変更しています。これによって、特定の操作に対して計算量を指定する事を回避しています。
- P2786R0 Trivial relocatability options - WG21月次提案文書を眺める(2023年02月)
- P1144R6 Object relocation in terms of move plus destroy - WG21月次提案文書を眺める(2022年06月)
- P1144R8
std::is_trivially_relocatable
- WG21月次提案文書を眺める(2023年05月) - P3055 進行状況
P3056R0 what ostream exception
現在例外を投げる際に避けることのできない動的メモリ確保を回避する提案。
標準ライブラリにあるstd::exception
派生クラスは.what()
メンバ関数からエラーメッセージを返すためにそのコンストラクタで文字列を受け取りますが、動的に構成した文字列をstd::string
に保持している状態で渡そうとする場合、文字列をコピーして受け取る以外の選択肢がありません。
void f(int n) { std::string err_msg = std::to_string(n); std::runtime_error err{err_msg}; // コピーされる throw err; }
これは、std::exception
派生クラスのstd::string
を受け取るコンストラクタはconst std::string&
を受け取るものしかないためです。
また、このように例外が発生するコンテキストでエラーメッセージを動的に構成する場合、その作業そのものに伴って動的メモリ確保が発生しています。例えば例外の.what()
が呼ばれない場合、このコストは余分なものとなります。
この提案は、std::exception
派生クラスおよびstd::exception
に2種類のメンバ関数を追加することによって、この2つの動的メモリ確保を回避もしくは遅延させ、ライブラリ実装者およびそのユーザーが動的メモリ確保を制御できる様にしようとするものです。
追加するのは次の2つです
std::exception
派生クラスのコンストラクタにstd::string&&
を受け取るコンストラクタを追加するstd::exception
の.what()
のオーバーロードとして、std::ostream&
を受け取りエラーメッセージの構築と出力まで行うオーバーロードを追加する
1つ目の変更によって、std::exception
派生クラスにエラーメッセージのstd::string
をムーブ渡しできる様になり、コピーに伴う動的メモリ確保を回避することができます。
void f(int n) { std::string err_msg = std::to_string(n); std::runtime_error err{std::move(err_msg)}; // ムーブされる throw err; }
2つ目の変更ではさらに、例外オブジェクト内部に必要な情報を保持しておき、エラーメッセージが必要になったタイミングでエラーメッセージをオンデマンドに構成することが可能になります。
class runtime_error_v2 : virtual public runtime_error_v2 { private: const int m; const std::source_location location; public: runtime_error_v2(int n, const std::source_location location) : m{n} , location{location} {} virtual std::ostream& what(std::ostream& os) const noexcept override { // 呼ばれてからメッセージを構成する return os << "file: " << location.file_name() << '(' << location.line() << ':' << location.column() << ") `" << location.function_name() << "`: " << "value: " << n << '\n'; } }; void f(int n) { std::runtime_error err{n, std::source_location::current()}; throw err; }
P3057R0 Two finer-grained compilation model for named modules
名前付きモジュールの依存関係管理について、より細かい単位で依存関係を管理する方法についての報告書。
名前付きモジュールでは、ヘッダファイルとは異なり個々のモジュールが1つの翻訳単位を成しているため、プログラム全体をビルドするためにはその依存関係を把握した上で依存関係の根本から順番にビルドしていく必要があります。そのため、インクリメンタルビルド等においては、ある1つのファイルの変更がより多くのモジュールや翻訳単位のリビルドを引き起こす可能性があります。
この文書は、この問題を軽減するために、より細かい単位で依存関係管理を行うコンパイルモデルを説明するものです。
この文書で挙げられているモデルは2つあります。
- 使用したファイルベースのソリューション
- 宣言のハッシュによるソリューション
この2つの方法はClangのプラグインを通して既に試すことができるようで、文書中でも実際のデモの様子が報告されています。
P3059R0 Making user-defined constructors of view iterators/sentinels private
<ranges>
の内部イテレータ型のコンストラクタを非公開にする提案。
<ranges>
にある各種のview
型は、その動作の実装のほとんどの部分をイテレータによって行なっています。その様なイテレータは構築時に親のview
を受け取りそのポインタを保存しますが、そのコンストラクタは親のview
型からアクセス可能であれば良いはずで、他のところからアクセスできる必要はありません。
現在のところ、標準のRangeアダプタのview
型のイテレータのその様なコンストラクタは、ものによってアクセスできたりできなかったりします。
int main() { auto base = std::views::iota(0); auto filter = base | std::views::filter([](int) { return true; }); // 内部イテレータ型のコンストラクタが呼べる(場合もある) auto begin = decltype(filter.begin())(filter, base.begin()); // ok auto end = decltype(filter.end() )(filter); // ok }
この提案は、この様なコードはエラーとなるべきで、標準のRangeアダプタのview
型のイテレータのコンストラクタは一部を除いて公開されるべきではない、とするものです。
上記のコードは実はGCCにおいてはエラーになります。それは、GCCのfilter_view
のイテレータの実装が親のfilter_view
を参照ではなくポインタで受け取る様になっているためです。実装の観点からは、これによってfilter_view
のbegin()
内では構築時にthis
を渡すだけですみ、イテレータ側もaddresof()
の呼び出しを適用する必要がなくなります。
現在の規定に照らせばGCCのこの実装は間違っていますが、これはview
の実装詳細の部分であり、本来公開されるべきではないものが公開されていることによる副作用と見なすことができます。また、このGCCのfilter_view
におけるイテレータの実装は、chunk_view
のイテレータにおいては規格でそのように指定されており一貫していません。このことからも、これらのコンストラクタは公開されないのをデフォルトにするのが望ましいと言えます。
この提案の対象はあくまで実装のために使用されるコンストラクタを非公開化するもので、デフォルトコンストラクタやムーブコンストラクタ、変換コンストラクタなどを非公開にしようとするものではありません。
P3060R0 Add std::ranges::upto(n)
0から指定した数の整数シーケンスを生成するRangeアダプタ、views::upto
の提案。
この提案のviews::upto(n)
はviews::iota(0, n)
と同じシーケンスを生成します
import std; int main() { // iota(0, n) for (int i : std::views::iota(0, 10)) { std::println("{} ", i); } std::println(""); // upto(n) for (int i : std::views::upto(10)) { std::println("{} ", i); } }
どちらも0 1 2 3 4 5 6 7 8 9
が出力されます。
このため実装はごく簡単に行うことができます
namespace std::ranges { // ranges::upto 実装例 inline constexpr auto upto = [] <std::integral I> (I n) { return std::views::iota(I{}, n); }; namespace views { using ::std::ranges::upto; } }
これだけだとiota
で十分にしか見えませんが、upto
の意義は符号なし整数型で同じことをする場合の微妙な使用感の悪さを改善することにあります。
void f(const std::vector<int>& vec) { auto seq1 = std::views::iota(0, vec.size()); // ng auto seq2 = std::views::upto(vec.size()); // ok }
整数値a, b
(a < b
として)によってviews::iota(a, b)
の様にする場合、a, b
の型は異なっていても構いませんが少なくとも符号有無は一致している必要があります(これは、iota_view
の推論補助の制約によって要求されます)。この様な制約は、符号有無が混在した整数型の比較が暗黙変換の結果として意図通りにならなくなる場合があり、それを防止するためのものです。
そのため、上記例のように符号有無が混在した整数値によって指定するとコンパイルエラーとなります。正しくはviews::iota(0u, vec.size())
とすべきですが、出力されるエラーメッセージも難しくこの原因を推察するのは容易ではありません。
upto
はシーケンス終端の整数値を1つ指定するだけで、先頭の値はその整数型をデフォルト構築して(0
が)補われるため、この問題を回避することができます。
また、同じシーケンスを生成する際にはわずかではありますがviews::iota
よりも短く書くことができ、その意図も明確になります。
P3061R0 WG21 2023-11 Kona Record of Discussion
2023年11月に行われたKona会議の全体会議における議事録。
会議期間中の各SGの作業報告や、LWG/CWGを通過した提案の投票の様子が記載されています。
P3062R0 C++ Should Be C++ - Presentation
P3023の紹介スライド。
EWG/LEWGのメンバに向けてP3023の主張を紹介したものです。
プレゼンテーション用のスライドなので、文章よりも行間が補われている部分があり、主張が分かりやすくなっています。
P3066R0 Allow repeating contract annotations on non-first declarations
関数の最初の宣言にのみ契約注釈を行えるという制限を撤廃する提案。
現在C++26に向けて議論が進められている契約プログラミング機能においては、関数に対する事前条件・事後条件は関数の最初の宣言でのみ行うことができ、たとえ内容が同じだったとしても再宣言で契約注釈を指定する(あるいは再宣言のみで契約を行う)ことはできません。
// 最初の宣言(ヘッダ内など) int f(const int n) pre(n < 100) post(r: r == n); int g(); // 再宣言、f()の定義(翻訳単位内) int f(const int n) pre(n < 100) // ng post(r: r == n) // ng { return n; } int g() post(r: -10 < r) // ng { return 20; }
これは、同じ関数に対して異なる翻訳単位で異なる契約注釈が行われてしまうことを防止するための制限です。
関数の宣言と定義がヘッダファイルと実装ファイルに分割されている場合、多くのユーザーはヘッダに書いた宣言をコピペして実装ファイルにおける定義を書き始めますが、その関数に契約がなされている場合契約注釈を削除しないとコンパイルエラーになることになります。これは驚くべき動作かもしれません。
クラスのメンバ関数の定義など、関数の宣言と定義が離れていてそこで使用されるエンティティが直接的に見えていない場合、契約注釈がそれを表示しなおかつそれが繰り返されることでコードの可読性を向上させられる可能性があります。
// Widget.h struct Widget { int f() const noexcept pre(i > 0); ... // much further below: private: int i; }; // Widget.cpp int Widget::f() const noexcept pre(i > 0) { return i * i; // using i here! }
元々、C++20で一旦導入されていた契約プログラミング機能では、契約注釈のリストが同じであるという制約の下で再宣言でも契約注釈を行うことができました。初期のMVPにもこれは受け継がれていましたが、後ほど削除されました。なぜなら、当初の仕様では契約注釈のリストについての同一性の定義がなく、どのように同一であるとするのかが不明だったためです。GCCの契約機能の実験実装(C++20の機能ベース)では契約条件式のODRベースの同一性を判定して実装されている様です。
しかし後で、異なる翻訳単位で同じ関数の最初の宣言が複数含まれるプログラムがwell-formeddであるかを指定する必要が出てきたことで、結局契約注釈の同一性の定義を行わなければならなくなった様です。そのため、これは解決すべき問題としてリストアップ(P2896R0)されており、その解決はP2932R2で提案されています。
この提案は、P2932R2で提案されている契約注釈の同一性の定義を採用することで、最初の宣言にある契約注釈を後の宣言で繰り返すことができる様にしようとするものです。
P2932R2で提案されている契約注釈の同一性の定義は次の様なものです
関数宣言
d1
の契約注釈c1
と関数宣言d2
上の契約注釈c2
は、仮引数名・戻り値名・テンプレートパラメータ名が異なることを除いて、 その述語(契約条件式)p1, p2
がそれぞれ宣言d1, d2
に対応する関数定義上に置かれた場合にODRを満たしているならば、c1
とc2
は同じ契約注釈である
この提案はこの定義を採用した上で、C++20時点の仕様だった、関数の後の宣言は最初の宣言と同じ契約注釈を指定するか契約注釈を省略するかのどちらかを行う、というものを復活させることを提案しています
この提案ではあくまでこのことだけを提案していて、最初の宣言で契約注釈を省略して後の宣言でのみ指定する、ことを可能にすることは提案していません。
P3070R0 Formatting enums
列挙型の値を簡単にstd::format
にアダプトさせるための、format_as
の提案。
C++23時点のstd::format()
(std::print
)で自前の列挙型を出力しようとする時、主に2つの方法があります。
namespace kevin_namespacy { // フォーマットしたい列挙型 enum class film { house_of_cards, american_beauty, se7en = 7 }; } // 1. フォーマッター特殊化を定義 template <> struct std::formatter<kevin_namespacy::film> : formatter<int> { auto format(kevin_namespacy::film f, format_context& ctx) { return formatter<int>::format(std::to_underlying(f), ctx); } }; int main() { using kevin_namespacy::film; film f = film::se7en; // 2. 基底の整数値を出力 auto s = std::format("{}", std::to_underlying(f)); }
1つはその列挙型のためにstd::formatter
を特殊化してフォーマット方法を定義することです。ただし、この例のように整数型のフォーマッタを再利用したとしてもそれなりの量のボイラープレートコードの記述が必要となります。また、フォーマット方法の定義を同じ名前空間で行うことができず、列挙型とそのフォーマッタの定義が空間的に別れてしまいます。
もう1つはstd::to_underlying()
によって列挙値に対応する整数値を取得してそれを出力する方法です。これはフォーマット時に常にstd::to_underlying()
の呼び出しが必要となります。
この提案は、これらの方法の欠点を改善したフォーマットのカスタマイズ方法を提案するものです。
この提案では、std::format
に対してformat_as()
というカスタマイズポイントを導入することを提案しています。
namespace kevin_namespacy { // フォーマットしたい列挙型 enum class film { ... }; // filmのためのカスタムフォーマット定義 auto format_as(film f) { return std::to_underlying(f); } }
format_as()
はstd::format()
呼び出し内からADLによって発見される関数であり、フォーマット対象の値(ここでは列挙値)を受け取ってそれを既にフォーマット可能な他の型の値(整数値や文字列など)に変換して返すようにしておく必要があります。
この方法のメリット・目的は次の様なものです
- 列挙型のためのフォーマットカスタマイズ方法の単純化
- 列挙型のフォーマット効率を向上
- 既にフォーマッタ特殊化が存在する場合、フォーマッタを経由しないことでフォーマットのパフォーマンスを向上させられる
- 後方互換性を確保し、
std::format
への移行を促進する
提案より、他の例
enum class color { red, green, blue }; auto format_as(color c) -> std::string_view { switch (c) { case color::red: return "red"; case color::green: return "green"; case color::blue: return "blue"; } } auto s = std::format("{}", color::red); // s == "red"
この提案ではこれを列挙型に限って有効化することを提案していますが、この仕組みはより一般の型に対して拡張可能です。実際に、{fmt}
ライブラリではこの仕組みが列挙型に限らず一般の型に対して有効化された上で出荷されています。
P3071R0 Protection against modifications in contracts
↓
P3071R1 Protection against modifications in contracts
契約注釈内から参照されるローカル変数と関数引数は暗黙的にconst
として扱われるようにする提案。
現在のContracts MVP仕様では、契約注釈内での意図しないプログラム状態の変更に対する保護が欠けているため、それを追加しようとする提案です。次のようなことを提案しています
- contract context(契約コンテキスト)は契約注釈内の条件式
- その文法はP2961R2で提案されているnatural syntaxのもの
- 契約コンテキストの部分式であり、オブジェクト型
T
の自動変数、または自動変数に対するT
型の構造化束縛を指名するid式は、const T
型の左辺値(lvalue) - 契約コンテキストの部分式であり、自動変数である
T
の参照を指名するid式は、const T
型の左辺値(lvalue) - 契約コンテキストの部分式であるラムダ式がコピーによって非関数エンティティをキャプチャする場合、暗黙に宣言された(クロージャオブジェクトの)メンバ型は
T
だが、ラムダの本体内でそのようなメンバを指名するとラムダがmutable
でない限りconst
左辺値が返される(これは通常通り)- ラムダ式が参照によってそのようなエンティティをキャプチャする場合、その参照を指名するid式は、
const T
型の左辺値(lvalue)
- ラムダ式が参照によってそのようなエンティティをキャプチャする場合、その参照を指名するid式は、
- 契約コンテキストの部分式で現れる
this
式はcv X
へのポインタを示すprvalue - 契約コンテキストの部分式であるラムダ式が
T
へのポインタであるthis
をキャプチャする場合、暗黙に宣言された(クロージャオブジェクトの)メンバ型はconst T
へのポインタ
提案文書より、サンプルコード。
int global = 0; int f(int x, int y, char *p, int& ref) pre((x = 0) == 0) // proposal: ill-formed、const左辺値への代入 pre((*p = 5)) // OK pre((ref = 5)) // proposal: ill-formed、const左辺値への代入 pre(std::same_as_v<decltype(ref), int&>) // OK; 結果はtrue pre((global = 2)) // OK pre([x] { return x = 2; }()) // error: xはconst pre([x] mutable { return x = 2; }()) // OK, 関数引数xのコピーを変更する pre([&x] { return x = 2; }()) // proposal: ill-formed、const左辺値への代入 pre([&x] mutable { return x = 2; }()) // proposal: ill-formed、const左辺値への代入 post(r: y = r) // error: yはconstではないので事後条件で使用できない { contract_assert((x = 0)); // proposal: ill-formed、const左辺値への代入 int var = 42; contract_assert((var = 42)); // proposal: ill-formed、const左辺値への代入 static int svar = 1; contract_assert((svar = 1)); // OK return y; } struct S { int dm; void mf() /* not const */ pre((dm = 1)) // proposal: ill-formed、const左辺値への代入 pre([this]{ dm = 1; }()) // proposal: ill-formed、const左辺値への代入 pre([this] () mutable { dm = 1; }()) // proposal: ill-formed、const左辺値への代入 pre([*this]{ dm = 1; }()) // error: ill-formed、const左辺値への代入 pre([*this] () mutable { dm = 1; }()) // OK, *thisのコピーを変更 {} };
proposalとコメントされているところがこの提案によって動作が変更されるところです。メンバ関数の契約注釈からthis
を使用する場合、それはconst
メンバ関数内であるかのように扱われます。
この提案は既にSG21においてMVPに採用することに合意されているようです。
P3072R0 Hassle-free thread attributes
スレッドへの属性指定APIについて、集成体と指示付初期化によるAPIの提案。
P2019ではstd::thread/jthread
に対してスレッド属性(のうちスレッド名とスタックサイズ)を指定できるようにすることを提案しています。そのAPIについては揺れているようで、P2019のリビジョン毎に変化している他、P3022では既存のライブラリに倣った異なるAPIが提案されています。
この提案は、P2019とP3022とも異なるAPIを提案するものです。
P2019R4では、属性ごとに異なる型を用意して、スレッドのコンストラクタ先頭でそれを受け渡します。P3022では、1つのスレッド属性クラスに全てのスレッド属性をまとめて、それをコンストラクタ先頭で受け渡します。
この提案は、P3022のアプローチに近いものですが、P3022とは異なりスレッド属性クラスを集成体として、それをコンストラクタ先頭で渡します。
// P2019R4 std::jthread thr(std::thread_name("worker"), std::thread_stack_size_hint(16384), [] { std::puts("standard"); }); // P3022R0 std::jthread::attributes attrs; attrs.set_name("worker"); attrs.set_stack_size_hint(16384); std::jthread thr(attrs, [] { std::puts("standard"); }); // この提案 std::jthread thr({.name = "worker", .stack_size_hint = 16384}, [] { std::puts("standard"); });
この提案のAPIは、P3022の利点(属性を1つにまとめられる、既存の慣行に従っている)という点を受け継ぎながら、よりユーザーにとって使いやすい構文で属性を指定することができます。
この実装はまず、std::thread
内部にスレッド属性クラスを定義したうえで
class thread { ... public: // スレッド属性集成体 struct attributes { std::string const &name = {}; std::size_t stack_size_hint = 0; }; ... };
これを受け取るコンストラクタをstd::thread
とstd::jthread
に追加します
class thread { ... // 追加するコンストラクタ template<class Attrs = attributes, class F, class... Args> requires std::is_invocable_v<F, Args...> explicit thread(Attrs, F &&, Args &&...); ... }; class jthread { ... // 追加するコンストラクタ template<class Attrs = thread::attributes, class F, class... Args> requires std::is_invocable_v<F, Args...> explicit jthread(Attrs, F &&, Args &&...); ... };
このようにすることで、先程のようにコンストラクタ引数内での指示付初期化による属性指定が可能になります。さらに、ベンダ定義の独自属性指定を使用することもできます。
std::thread t5(__gnu_cxx::posix_thread_attributes{.schedpolicy = SCHED_FIFO}, std::puts, "vendor extension");
また、将来属性が増えた場合は新しい属性クラスを用意して、これらのコンストラクタのデフォルトテンプレートパラメータを差し替えることでAPI/ABIの互換性を保ったまま拡張することができます。
- P2019R4 Thread attributes - WG21月次提案文書を眺める(2023年10月)
- P3022R0 A Boring Thread Attributes Interface - WG21月次提案文書を眺める(2023年10月)
- P3072 進行状況
P3074R0 constexpr union lifetime
定数式において、要素の遅延初期化のために共用体を用いるコードを動作するようにする提案。
この提案の動機は、現在議論中のstd::inplace_vector
を定数式でも利用できるようにしようとするもので、そこでの問題は次のようなものです
template <typename T, size_t N> struct FixedVector { // 単一要素union、ストレージ領域のオブジェクトを構築しない union U { // storageの各要素の生存期間は外側のFixedVectorが管理する constexpr U() { } constexpr ~U() { } T storage[N]; // 要素が挿入されるまでは初期化したくない }; U u; size_t size = 0; // note: we are *not* constructing storage constexpr FixedVector() = default; constexpr ~FixedVector() { std::destroy(u.storage, u.storage+size); } constexpr auto push_back(T const& v) -> void { std::construct_at(u.storage + size, v); // ng、u.storageはアクティブメンバではない ++size; } }; constexpr auto silly_test() -> size_t { FixedVector<std::string, 3> v; v.push_back("some sufficiently longer string"); return v.size; } static_assert(silly_test() == 1);
このコードは合法的に動作しないようです。例えば、MSVC/EDG/GCC13.21までは動作しますが、clangや最新のGCCはこれを拒否します。
問題は、共用体のコンストラクタがメンバを初期化していないため、その唯一のメンバstorage
オブジェクトの生存期間が開始されていないため、その領域(の一部)を遅延初期化しようとすると非アクティブメンバに対するアクセスになってしまい、これが定数式で許可されていないためにエラーとなることです。
とはいえ、共用体のコンストラクタでstorage
を初期化してしまうと、storage
の全ての要素の初期化が必要になってしまいます。要素型がデフォルトコンストラクタを持たない場合はこれはエラーになります。また、共用体を利用せずにこのような遅延初期化を行うことはできません(aligned_storage
のようなものはT
ではない別の型の領域を再利用する形になる)。
この提案は、このような共用体使用時の非アクティブメンバアクセスを定数式でも行えるようにしようとするもので、3つのアプローチを紹介しています。
- 上記のようなストレージのための特別扱いされたライブラリ型
std::uninitialized<T>
を提供する- まさに上記の
U::storage
を提供するための汎用型、要素型がimplicit-lifetime typeでないならば各要素の生存期間は自動的に開始されない - その初期化と破棄の管理は完全に利用者の責任
- コンパイラの特別扱いなどにより、上記の問題を回避する
- まさに上記の
- 共用体の最初のメンバがimplicit-lifetime typeならば、共用体の生存期間開始時に暗黙的にそのメンバの生存期間を開始する
- 上記例の場合、配列オブジェクト
storage
の生存期間は開始されるが、各要素の生存期間は開始されず初期化もされない
- 上記例の場合、配列オブジェクト
- 初期化を伴うことなく、メンバの生存期間だけをユーザーが明示的に開始する方法を提供する
- 2の方法の問題点を回避する
2の方法の問題は、共用体が複数のimplicit-lifetime typeメンバを持っていてコンテキストに応じて使い分けたい場合に先頭以外のメンバの生存期間(だけ)を開始する方法がないことです。
union U {
T x[N];
U y[M];
} u;
例えばこのような共用体の場合、2の仕様を有効化したとするとU::x
だけは定数式で初期化せずに使用できますが、U::y
は最初の問題と同じことに悩まされます。そのため、3の方法では暗黙的ではなく明示的に、共用体の特定のメンバの生存期間だけを開始するライブラリ関数を提供することでこれを解決します。
現在の標準ライブラリにはそれに近いことを行ってくれる関数std::start_lifetime_as()
がすでに存在しています
template<class T> T* start_lifetime_as(void* p) noexcept;
しかし、これが行うことは今回解決したい問題の解消とは少し異なっており、いくつか問題があります
constexpr
指定されていない- 実行時に使用されないように
if consteval
で囲う必要がある - 型名を指定しなければならない
- 戻り値を使用しなければならない
- 実装によって
[[nodiscard]]
が付加される場合警告されてしまう
- 実装によって
template <typename T, size_t N> struct FixedVector { union U { constexpr U() { } constexpr ~U() { } T storage[N]; }; U u; size_t size = 0; // note: we are *not* constructing storage constexpr FixedVector() { if consteval { std::start_lifetime_as<T[N]>(&u.storage); } } };
そこで、この提案では共用体の特定メンバの生存期間を開始することに特化した関数を改めて追加することを提案しています
template<class T> constexpr void start_lifetime(T*);
ただし、この関数で生存期間を明示的に開始できるのはT
がimplicit-lifetime typeの場合に限ります。
これを用いると、先ほどの例は次のようになります
template <typename T, size_t N> struct FixedVector { union U { constexpr U() { } constexpr ~U() { } T storage[N]; }; U u; size_t size = 0; // note: we are *not* constructing storage constexpr FixedVector() { std::start_lifetime(&u.storage); } };
また、この関数を利用すると1の方法を簡単に実装することができるようになります。
この提案では、この3番目の方法をメインとして提案しています。
P3075R0 Adding an Undefined Behavior and IFNDR Annex
C++の規格書の付属としてコア言語の未定義動作のリストを追加する手続きについての提案。
P1705R0にてコア言語の未定義動作のリストを規格書に添付することが提案されています。そこでは、未定義動作を少なくとも1つのサンプルコードと共に例示しておくことで、言語の未定義動作を明確にするとともにそのリストをC++コミュニティに対して提供し、各未定義動作についての追跡を容易にすることを目的としていました。また、追加で診断不用のill-formed(IFNDR)のリストも同様に提供しようとしています。
この提案はその具体的なプロセスについてのもので、序文およびリストの各要素がどのような情報を伴うかについて提案するものです。
提案する文書構造としては、現在の規格書のコア言語のグループに準じた形でグループ化したうえで、その下にそのグループに属する未定義動作/IFNDRを要素として配置するものです。
各要素は次のようなレイアウトになります
- 問題を簡潔にまとめたタイトル
- メインの規格の関連する部分へのクロスリファレンス
- 標準のnote形式の問題の概要テキスト
- 問題が起こる場合を示すサンプルコード
転記はしませんが、UB/IFNDRのAnnexの序文も提案されています。