文書の一覧
全部で42本あり、SG22(C/C++相互互換性に関する研究グループ)のCの提案を除くと41本になります。
- P0288R9 move_only_function (was any_invocable)
- P0447R16 Introduction of std::hive to the standard library
- P0627R5 Function to mark unreachable code
- P0849R8 auto(x): decay-copy in the language
- P1018R13 C++ Language Evolution status 🦠 pandemic edition 🦠 2021/08–2021/09
- P1072R10 basic_string::resize_and_overwrite
- P1885R7 Naming Text Encodings to Demystify Them
- P2012R1 Fix the range-based for loop, Rev1
- P2036R3 Changing scope for lambda trailing-return-type
- P2066R9 Suggested draft TS for C++ Extensions for Minimal Transactional Memory
- P2093R9 Formatted output
- P2128R6 Multidimensional subscript operator
- P2214R1 A Plan for C++23 Ranges
- P2266R2 Simpler implicit move
- P2276R1 Fix cbegin
- P2278R1 cbegin should always return a constant iterator
- P2314R3 Character sets and encodings
- P2316R2 Consistent character literal encoding
- P2322R4 ranges::fold
- P2348R1 Whitespaces Wording Revamp
- P2362R3 Remove non-encodable wide character literals and multicharacter wide character literals
- P2363R1 Extending associative containers with the remaining heterogeneous overloads
- P2372R3 Fixing locale handling in chrono formatters
- P2388R2 Minimum Contract Support: either Ignore or Check_and_abort
- P2408R1 Ranges views as inputs to non-Ranges algorithms
- P2418R1 Add support for std::generator-like types to std::format
- P2419R1 Clarify handling of encodings in localized formatting of chrono types
- P2430R0 Slides: Partial success scenarios with P2300
- P2431R0 Presentation: Plans for P2300 Revision 2
- P2432R0 Fixing istream_view
- P2435R0 2021 Summer Library Evolution Poll Outcomes
- P2436R0 2021 September Library Evolution Polls
- P2437R0 Support for #warning
- P2438R0 std::string::substr() &&
- P2439R0 Slides for P2415R1, what is a view?
- P2440R0 ranges::iota, ranges::shift_left, and ranges::shift_right
- P2441R0 views::join_with
- P2442R0 Windowing range adaptors: views::chunk and views::slide
- P2443R0 views::chunk_by
- P2444R0 The Asio asynchronous model
- P2446R0 views::move
- おわり
P0288R9 move_only_function
(was any_invocable
)
ムーブのみが可能で、関数呼び出しのconst
性やnoexcept
性を指定可能なstd::function
であるstd::any_invocable
の提案。
以前の記事を参照
- P0288R6 :
any_invocable
- WG21月次提案文書を眺める(2020年8月) - P0288R7 :
any_invocable
- WG21月次提案文書を眺める(2020年9月) - P0288R8
move_only_function
(wasany_invocable
) - WG21月次提案文書を眺める(2021年7月)
このリビジョンでの変更は、提案する文言の微修正のみの様です。
この提案はLWGのレビューを通過し次の全体会議で投票にかけられることが決まっています。
P0447R16 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月)
このリビジョンでの変更は、望ましいclear()
の動作の説明を追加した事、リファレンス実装へのリンクを変更した事、common
ではないrange
を受けられるようにrange
コンストラクタを修正した事などです。
P0627R5 Function to mark unreachable code
到達不可能なコード領域であることを示す、std::unreachable()
の提案。
あるコードブロックについて、プログラマはそこが実行されないことを知っていたとしても、コンパイラにとってはそうではありません。そのような場合に、コンパイラにそれを通知する方法があるとより効率的なプログラムを作成できる可能性があります。例えば、switch
文でよく見る事ができます。
void do_something(int number_that_is_only_0_1_2_or_3) { switch (number_that_is_only_0_1_2_or_3) { case 0: case 2: handle_0_or_2(); break; case 1: handle_1(); break; case 3: handle_3(); break; } }
このような場合、コンパイラは4以上の入力に対して処理をスキップするコードを生成します。この時、4以上の入力が決して来ないことがわかっていて、それをコンパイラに伝える事ができればそのような余分なコードの生成を抑止する事ができます。
他にも有用な場合が多々あるため、C++の処理系でもそのような機能を持っているものがあります。
このようなサポートのない実装でも意図的にゼロ除算を行い未定義動作を挿入する事で到達不能性を表現できますが、それは直感的ではなく推奨されません。この提案は、標準的な方法によって到達不可能であることを表現できるようにしようとするものです。
この提案では、std::unreachable()
という関数によってそれを行います。
namespace std { [[noreturn]] void unreachable(); }
この関数は呼び出されると未定義動作であると規定されており(正確には、事前条件が常に満たされないように規定されている)、呼び出されているコンテキストは未定義動作であることからコンパイラはその場所が実行されないと仮定する事ができ、それによって到達不能性を表現します。
先ほどのswitch
文では次のように使用できます。
void do_something(int number_that_is_only_0_1_2_or_3) { switch (number_that_is_only_0_1_2_or_3) { case 0: case 2: handle_0_or_2(); break; case 1: handle_1(); break; case 3: handle_3(); break; default: std::unreachable(); } }
std::unreachable()
の振る舞いが未定義動作であることを選択したのは次のような理由によります
- 呼び出された時の特定のアクションを規定しないことで、実装は自由な振る舞いを選択できる
- 例えば、デバッグビルドにおいてトラップを発動するなど
- clangは
__builtin_unreachable()
の呼び出しを未定義動作であると規定している - 動作が未定義であることで定数式では実行できず、必然的に
constexpr
コンテキストで呼ばれた場合の振る舞いが規定される
また、[[unreachable]]
のような属性ではなく関数が好まれた一つの理由として、その実装を後から変更する事が可能となるためというのが挙げられています。
P0849R8 auto(x)
: decay-copy in the language
明示的にdecay-copyを行うための構文を追加する提案。
以前の記事を参照
- P0849R4 auto(x): decay-copy in the language - [C++]WG21月次提案文書を眺める(2020年10月)
- P0849R5 auto(x): decay-copy in the language - [C++]WG21月次提案文書を眺める(2020年11月)
- P0849R6 auto(x): decay-copy in the language - [C++]WG21月次提案文書を眺める(2020年12月)
- P0849R7 auto(x): decay-copy in the language - [C++]WG21月次提案文書を眺める(2021年02月)
このリビジョンでの変更は、提案する文言の調整のみのようです。
この提案は、CWGとLWGでのレビューを終え、次の全体会議で投票にかけられることが決まっています。
P1018R13 C++ Language Evolution status 🦠 pandemic edition 🦠 2021/08–2021/09
EWG(コア言語への新機能追加についての作業部会)が2021/08–2021/09の間に議論した提案やIssueのリストや将来の計画、テレカンファレンスの状況などをまとめた文書。
8月には以下の提案がEWGでの投票にかけられ、P2138R4以外はCWGに送られることが決まっています。
- P2138R4 Rules of Design <=> Wording engagement
- P2266R1 Simpler implicit move
- P2128R5 Multidimensional subscript operator
- P2036R2 Changing scope for lambda trailing-return-type
- P2334R1 Add support for preprocessing directives elifdef and elifndef
- P2066R7 Suggested draft TS for C++ Extensions for Transaction Memory Light
- P2360R0 Extend init-statement to allow alias-declaration
- P2246R1 Character encoding of diagnostic text
- P2314R2 Character sets and encodings
- P2316R1 Consistent character literal encoding
ただし、P2266R1にはclangにおける実装経験より破壊的変更となることが指摘されており、CWGあるいは本会議投票で否決される可能性があります。
P1072R10 basic_string::resize_and_overwrite
std:string
に領域(文字長)を拡張しつつその部分を利用可能にする為のメンバ関数resize_and_overwrite()
を追加する提案。
以前の記事を参照
- P1072R6
basic_string::resize_and_overwrite
- [C++]WG21月次提案文書を眺める(2020年12月) - P1072R7
basic_string::resize_and_overwrite
- [C++]WG21月次提案文書を眺める(2021年02月) - P1072R8
basic_string::resize_and_overwrite
- [C++]WG21月次提案文書を眺める(2021年06月) - P1072R9
basic_string::resize_and_overwrite
- [C++]WG21月次提案文書を眺める(2021年08月)
このリビジョンでの変更は、提案する文言の調整です。
この提案はLWGのレビューを終え、次の全体会議で投票にかけられます。
P1885R7 Naming Text Encodings to Demystify Them
システムの文字エンコーディングを取得し、識別や出力が可能なライブラリを追加する提案。
以前の記事を参照
- P1885R3 Naming Text Encodings to Demystify Them - [C++]WG21月次提案文書を眺める(2020年9月)
- P1885R4 Naming Text Encodings to Demystify Them - [C++]WG21月次提案文書を眺める(2020年11月)
- P1885R5 Naming Text Encodings to Demystify Them - [C++]WG21月次提案文書を眺める(2021年02月)
- P1885R6 Naming Text Encodings to Demystify Them - [C++]WG21月次提案文書を眺める(2021年08月)
このリビジョンでの変更は
aliases()
の戻り値型をstring_view
からaliases_view
に変更aliases_view
はcopyable
でありview
かつborowed_range
かつrandom_access_range
である軽量の型で、そのvalue_type/reference
はconst char*
となります。
text_encoding::environment()
が実行時のロケール変更の影響を受けるように変更name()
とaliases()
で返される名前の間の関連性を明確にしたname()
がnulltpr
を返すことがあるように変更text_encoding{text_encoding::id::unknown}.name();
の様なとき
- 提案する文言の修正
などです。
P2012R1 Fix the range-based for loop, Rev1
現在のrange-based forに存在している、イテレーション対象オブジェクトの生存期間にまつわる罠を修正する提案。
以前の記事を参照
このリビジョンでの変更は、この提案による変更が破壊的変更になるかどうかの調査と議論の追加、回避策が解決策ではない理由の追加、コンパイラによる診断についての議論の追加、などです。
著者の方(Nicolai Josuttisさん)のツイートによると、この提案に関してこれ以上の作業はなされないようです・・・
P2036R3 Changing scope for lambda trailing-return-type
ラムダ式の後置戻り値型指定において、初期化キャプチャした変数を参照できるようにする提案。
以前の記事を参照
- P2036R1 Changing scope for lambda trailing-return-type - [C++]WG21月次提案文書を眺める(2021年01月)
- P2036R2 Changing scope for lambda trailing-return-type - [C++]WG21月次提案文書を眺める(2021年07月)
このリビジョンでの変更は、提案する文言の修正です。
この提案は現在CWGでのレビューを受けています。そこを通過すれば、全体会議での投票に進みます。
P2066R9 Suggested draft TS for C++ Extensions for Minimal Transactional Memory
現在のトランザクショナルメモリTS仕様の一部だけを、軽量トランザクショナルメモリとしてC++へ導入する提案。
以前の記事を参照
- P2066R2 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2020年05月)
- P2066R3 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2020年09月)
- P2066R4 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2020年10月)
- P2066R5 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2021年02月)
- P2066R6 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2021年03月)
- P2066R7 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2021年05月)
- P2066R8 Suggested draft TS for C++ Extensions for Minimal Transactional Memory - [C++]WG21月次提案文書を眺める(2021年07月)
このリビジョンの変更点は、いくつかのフィードバックに対応して文言を修正した事です。
この提案はLWCとCWGでのレビューが終了し、次の全体会議で投票にかけられるようです。そこで承認されれば、Transactional Memory TS(v2?)として発行されることになります。
P2093R9 Formatted output
std::format
によるフォーマットを使用しながら出力できる新I/Oライブラリstd::print
の提案。
以前の記事を参照
- P2093R0 Formatted output - [C++]WG21月次提案文書を眺める(2020年6月)
- P2093R1 Formatted output - [C++]WG21月次提案文書を眺める(2020年7月)
- P2093R2 Formatted output - [C++]WG21月次提案文書を眺める(2020年10月)
- P2093R3 Formatted output - [C++]WG21月次提案文書を眺める(2021年1月)
- P2093R4 Formatted output - [C++]WG21月次提案文書を眺める(2021年2月)
- P2093R5 Formatted output - [C++]WG21月次提案文書を眺める(2021年3月)
- P2093R6 Formatted output - [C++]WG21月次提案文書を眺める(2021年4月)
- P2093R7 Formatted output - [C++]WG21月次提案文書を眺める(2021年7月)
- P2093R8 Formatted output - [C++]WG21月次提案文書を眺める(2021年8月)
このリビジョンでの変更は、SG16の投票の結果を記載した事、提案する文言の修正、Pythonのprint
との違いを明確にしたことなどです。
この提案は主にエンコーディング周りの事を詰めるためにSG16で作業されていましたが、それが完了しC++23に向けてLEWGに転送されることになりました。
P2128R6 Multidimensional subscript operator
多次元コンテナサポートのために添字演算子([]
)が複数の引数を取れるようにする提案。
前回の記事を参照
- P2128R1 Multidimensional subscript operator - [C++]WG21月次提案文書を眺める(2020年5月)
- P2128R2 Multidimensional subscript operator - [C++]WG21月次提案文書を眺める(2020年7月)
- P2128R3 Multidimensional subscript operator - [C++]WG21月次提案文書を眺める(2021年2月)
- P2128R5 Multidimensional subscript operator - [C++]WG21月次提案文書を眺める(2021年4月)
このリビジョンでの変更は、CWGの指示に基づいて提案する文言を修正した事です。
この提案は、このリビジョンを持ってCWGのレビューが完了しており、次の全体会議で投票にかけられます。
P2214R1 A Plan for C++23 Ranges
C++23に向けてのrangeライブラリの拡張プランについてまとめた文書。
前回の記事を参照
このリビジョンでは、R0以降の作業の進行を反映しいくつかの提案へのリンクを追加した事と
- Rangeアダプタのパイプサポートのためのヘルパクラス(P2387R1)をTier 1へ追加
cache1(cache_latest)
をTier 1からTier 2へas_const
をTier3からTier1へflat_map
をTier1からTier3へ- 現在、
transform(f) | join
が正しく同じことをするため
- 現在、
transform_maybe
をTier1からTier3へcache1
に依存しているため
- 以前は省略されていたRangeアダプタをTier 3へ追加
shift_left/shift_right
をTier 1へ追加
などです。
P2266R2 Simpler implicit move
return
文における暗黙のムーブを改善する提案。
以前の記事を参照
- P2266R0 Simpler implicit move - [C++]WG21月次提案文書を眺める(2021年01月)
- P2266R1 Simpler implicit move - [C++]WG21月次提案文書を眺める(2021年03月)
このリビジョンでの変更は、提案する文言の修正と機能テストマクロの追加、EWGにおける投票の結果を記載した事、clangにおける実装経験について追記した事です。
この提案はCWGのレビューが終了し全体会議で投票にかけられることが決まっていますが、clangによる実装経験から破壊的変更の程度が大きく実装者から反対意見が提出されています。そのため、本会議において否決され再度の議論が必要となる可能性があるようです。
P2276R1 Fix cbegin
メンバ関数cbegin()
とフリー関数のstd::cbegin()/std::ranges::cbegin()
の不一致を修正し、std::span
のcbegin()
サポートを復活させる提案。
以前の記事を参照
このリビジョンでは、R0の時に提案していたcbegin/cend
に対する修正を提案しなくなりました。その代わりに、壊れたconst
性を無効化し回避策を実装できるようにすることを目標とするようになりました。
R1では、次の4つの事を提案します
std::span
にメンバ関数cbegin()/cend()
を追加- これはLEWGのレビューにおいて合意済
- コンテナが深い
const
性(deep constness)を提供するかどうかを検出するコンセプトを提供する - 浅い
cosnt
性によってバグを抱える場合、std::cbegin/std::cend
を無効にする- 理想的にはコンパイルエラーとしたいが、少なくとも非推奨にする
- 浅い
cosnt
性によってバグを抱える場合、std::ranges::cbegin/std::ranges::cend
を無効にする
なお、cbegin()/cend()
だけでなく、c
付き範囲アクセス関数(CPO)に対して同じことを提案しています。
そしてこれらの提案は全て、C++20に向けてのDefect Reportとする事が提案されています。
P2278R1 cbegin should always return a constant iterator
std::ranges::cbegin/cend
を拡張して、常にconst_iterator
を返すようにする提案。
以前の記事を参照
このリビジョンでの変更は、提案する文言を追加した事(ranges::cdata
を含むようにしたこと、view_interface
にcbegin/cend
を追加した)、views::const_range
をviews::as_const
に変更した事、深いconst
性を持つview
を扱えるようにviews::as_const
の定義を修正した事です。
P2314R3 Character sets and encodings
規格文書中の ~ character setという言葉を明確に定義し直す提案。
以前の記事を参照
- P2314R0 Character sets and encodings - [C++]WG21月次提案文書を眺める(2021年02月)
- P2314R1 Character sets and encodings - [C++]WG21月次提案文書を眺める(2021年03月)
- P2314R2 Character sets and encodings - [C++]WG21月次提案文書を眺める(2021年05月)
このリビジョンでの変更は、CWGからのフィードバックを反映した事です。
P2316R2 Consistent character literal encoding
#if
プリプロセッシングディレクティブの条件式において、文字リテラルをC++の式の意味論と同等に扱えるようにする提案。
以前の記事を参照
- P2316R0 Consistent character literal encoding - WG21月次提案文書を眺める(2021年02月)
- P2316R1 Consistent character literal encoding - WG21月次提案文書を眺める(2021年07月)
このリビジョンでの変更は、提案する文言の修正です。
この提案は、CWGのレビューを終えて次の全体会議で投票にかけられることが決まっています。
P2322R4 ranges::fold
range
アルゴリズムであるranges::fold
の提案。
以前の記事を参照
- P2322R0 ranges::fold - [C++]WG21月次提案文書を眺める(2021年02月)
- P2322R1 ranges::fold - [C++]WG21月次提案文書を眺める(2021年03月)
- P2322R2 ranges::fold - [C++]WG21月次提案文書を眺める(2021年04月)
- P2322R3 ranges::fold - [C++]WG21月次提案文書を眺める(2021年06月)
このリビジョンでの変更は、説明が少し修正されただけの様です。
P2348R1 Whitespaces Wording Revamp
ユニコードの仕様に従う形で、改行と空白を明確に定義する提案。
以前の記事を参照
このリビジョンでの変更は、Vertical TabとForm Feedを垂直方向のスペースではなく水平方向のスペースとして扱うようにしたこと(ユニコード規格には従っていたが、現在の文言及び実装には準じていなかった)、\n\r
など名前が付いていない文字によるシーケンスについてのメモの追記、P2314R2がベースとなるように文言を調整した事などです。
P2362R3 Remove non-encodable wide character literals and multicharacter wide character literals
エンコード可能ではない、あるいは複数文字を含むワイド文字リテラルを禁止する提案。
以前の記事を参照
- P2362R0 Make obfuscating wide character literals ill-formed - WG21月次提案文書を眺める(2021年04月)
- P2362R1 Make obfuscating wide character literals ill-formed - WG21月次提案文書を眺める(2021年07月)
- P2362R2 Make obfuscating wide character literals ill-formed - WG21月次提案文書を眺める(2021年08月)
このリビジョンでの変更は、提案する文言の調整とEWGにおける投票の結果を記載した事です。
P2363R1 Extending associative containers with the remaining heterogeneous overloads
連想コンテナの透過的操作を、さらに広げる提案。
以前の記事を参照
このリビジョンでの変更は、insert
やoperator[]
などのオーバーロードにstd::is_constructible_v<value_type, K&&, Args...>
の様な制約を要求しないようにしたこと、提案する文言を追加した事です。
P2372R3 Fixing locale handling in chrono formatters
<chrono>
のフォーマッタがロケール依存でありそれを制御できない問題を修正する提案。
以前の記事を参照
- P2372R1 Fixing locale handling in chrono formatters - WG21月次提案文書を眺める(2021年05月)
- P2372R2 Fixing locale handling in chrono formatters - WG21月次提案文書を眺める(2021年08月)
このリビジョンでの変更は、提案する文言の修正などです。
この提案はLWGでのレビューを終え、次の全体会議で投票にかけられます。
P2388R2 Minimum Contract Support: either Ignore or Check_and_abort
契約が破られた時に継続しないコントラクトサポートを追加する提案。
以前の記事を参照
- P2388R0 Abort-only contract support - WG21月次提案文書を眺める(2021年05月)
- P2388R1 Minimum Contract Support: either Ignore or Check_and_abort - WG21月次提案文書を眺める(2021年08月)
このリビジョンでの変更は
- 同じ関数が異なるファイル(翻訳単位)で異なる契約がなされている場合、ill-formed(診断不用)とする事を明確にした
- 参照ではない関数引数に対する事後条件についての議論を拡張
- 機能テストマクロの追加
std::unreachable()
との相互作用について記載std::unreachable()
は事前条件が満たされない事で到達不能性を表現しているため、そこに契約を用いると無限ループになる
- UBサニタイザの説明を追加
などです。
事後条件において関数引数を参照する場合、問題となるのは次の様なコードです
// ユーザーが見る宣言 int generate(int lo, int hi) [[pre lo <= hi]] [[post r: lo <= r && r <= hi]]; // 開発者が見る定義 int generate(int lo, int hi) { int result = lo; while (++lo <= hi) // loが更新される { if (further()) ++result; // loよりもゆっくりとインクリメントされる } return result; }
この時、generate()
の戻り値は呼び出された時点のlo
以上にはなりますが、関数終了時点のlo
よりも小さい可能性があります。すなわち、事後条件で関数引数を参照する場合どの時点の値を参照するかで条件の意味が変わってしまうのです。
契約された関数のユーザーが見るのは宣言であり、宣言には明確に「あなたが関数に渡したオブジェクトは変更されない(コピーして使用するので)」「戻り値の数値はあなたが渡した制限値の間に収まる(関数の実行中に作られた値ではない)」と書かれています(あるいはそう読み取ることができます)。人間は宣言をこの様に解釈するためツール(静的解析など)もそのように解釈すべきであり、C++の契約ランタイムチェックも同様にする必要があります。
また、非const
非参照関数引数の事後条件での使用を許可してしまうと、事後条件がムーブ後オブジェクトを読んでしまう事に繋がります。
// 宣言 string forward(string str) [[post r: r == str]]; // 定義 string forward(string str) // disallowed in our proposal { // ... return str; // implicit move } // 事後条件はムーブ後オブジェクトを読み取る(未定義動作)
この例ではよりユーザーの意図と外れていることが明確であり、ここでは未定義動作よりもコンパイルエラーが望ましいでしょう。
このため、この提案では非const
非参照関数引数を事後条件で参照するのはill-formedとしています。
P2408R1 Ranges views as inputs to non-Ranges algorithms
非Rangeアルゴリズムのイテレータに対する名前付き要件を、イテレータコンセプトで置き換える提案。
以前の記事を参照
このリビジョンでの変更は、common_range
ではない範囲の使用について議論を追加した事です。
P2418R1 Add support for std::generator-like types to std::format
std::generator
-likeな型に対する<format>
のサポートを追加する提案。
以前の記事を参照
このリビジョンでの変更は、LEWGでの投票の結果を記載したこと、提案する文言の改善などです。
この提案はC++20への欠陥報告(DR)とする事で合意がとれ、すでにLWGのレビューを終えて次の全体会議で投票にかけられることが決まっています。
P2419R1 Clarify handling of encodings in localized formatting of chrono types
<chrono>
のフォーマットにおいて、実行時ロケールが指定するエンコーディングとリテラルエンコーディングが異なる場合の振る舞いを規定する提案。
以前の記事を参照
このリビジョンでの変更は、SG16での投票結果を記載した事です。
この提案はSG16からLEWGへ、C++23に導入することを目指して転送されました。
P2430R0 Slides: Partial success scenarios with P2300
非同期処理における部分的な成功(Partial Success)を配信する(返す)際の、P2300のモデルにおける問題点について解説したスライド。
P2431R0 Presentation: Plans for P2300 Revision 2
P2300R2に向けて、これまで受け取ったフィードバック(疑問点)への回答をまとめたスライド。
P2432R0 Fixing istream_view
std::views::istream_view<T>()
の他のview
との非一貫性を正す提案。
std::views::istream_view<T>()
は関数であり、型名ではありません。したがって、次のようなことはできません。
int main() { std::istringstream mystream{"0 1 2 3 4"}; std::ranges::istream_view<int> v{mystream}; // 型名ではないので、このような初期化はできない std::ranges::basic_istream_view<int, char> v{mystream}; // これはok }
istream_view
は、std::ranges::basic_istream_view
というview
の実体の型に対してstd::views::istream_view
というヘルパ関数が用意されています。一方で<ranges>
の他のview
は、std::ranges::xxx_view
という実体の型に対してstd::views::xxx
という関数オブジェクト(CPO)が用意されており、istream_view
だけがこれらの命名規則の外にあります。
そのため、上に書いたようなコードは他のview
との一貫性のある自然な発想によって書かれますが、コンパイルエラーとなります。特に、for
ループと共に書かれた場合に理解不能なエラーメッセージを見る事ができるでしょう・・・
int main() { std::istringstream mystream{"0 1 2 3 4"}; for (int v : std::ranges::istream_view<int>{mystream}) { ... } }
この提案はこれらの問題を解決するべく、istream_view
の命名規則を他のview
と一貫させようとするものです。
この提案の後では、istream_view
周りは次のようになります。
namespace std::ranges { // basic_istream_viewクラスはそのまま template<movable Val, class CharT, class Traits> requires default_initializable<Val> && stream-extractable<Val, CharT, Traits> class basic_istream_view : public view_interface<basic_istream_view<Val, CharT, Traits>>; // charとwchar_tを予め嵌めた型エイリアスを追加 template<class Val> using istream_view = basic_istream_view<Val, char>; template<class Val> using wistream_view = basic_istream_view<Val, wchar_t>; namespace views { // 現在のviews::istream_view<T>()を削除し、views::istream<T> CPOを追加 template<typename T> inline constexpr /*unspecified*/ istream = /*unspecified*/; } }
これによって、std::ranges::istream_view<T>
は型名を示すようになりstd::views::istream<T>
はそれを生成する関数オブジェクト(CPO)となり、その他のview
との一貫性が保たれるようになります。
これらの解決はC++20へのDRとすることを提案しており、LEWGでのレビューでは合意が取れているようです。
P2435R0 2021 Summer Library Evolution Poll Outcomes
2021年の夏(7月から9月にかけて)に行われた、LEWGの全体投票の結果。
以下の5つの提案が投票にかけられ、P2138R4以外はLWGに転送されることが可決されています。また、その際に寄せられたコメントが記載されています。
- P2138R4 Rules of Design <=> Wording Engagement
- P2372R1 Fixing Locale Handling In Chrono Formatters
- P1206R6
ranges::to
- P0533R8 constexpr For
<cmath>
And<cstdlib>
- P2273R2 Making
unique_ptr
constexpr
P2436R0 2021 September Library Evolution Polls
2021年の秋(10月から12月にかけて)に予定されている、LEWGでの全体投票の予定表。
以下の5つの提案が投票にかけられる予定です。
- P2418R0 Add Support For
std::generator
-like Types Tostd::format
- P2415R1 What Is A view?
- P2432R0 Fix istream_view
- P2351R0 Mark All Library Static Cast Wrappers As
[[nodiscard]]
- P2291R2 Add Constexpr Modifiers To Functions
to_chars
Andfrom_chars
For Integral Types In<charconv>
Header
LEWGでの作業を完了してLWG(CWG)へ転送することを確認するための投票です。上の3つの提案はC++20へ逆適用することを目指しています。
P2437R0 Support for #warning
警告を表示するための#warning
プリプロセッシングディレクティブを追加する提案。
#warning
ディレクティブは#error
と同様にコンパイル時にプログラマに対してメッセージを発行する事ができますが、#error
とは異なりコンパイルを停止しません。これは、ライブラリ開発者などが利用者に向けて致命的ではない警告を表示するのに役立ちます。
主要なC/C++コンパイラのほとんどが既にこれを実装しておりデファクトスタンダードとなっています。加えて、C言語ではC23に向けてすでに#warning
ディレクティブが承認されているため、C++でも同じ機能をサポートする事でコンパイラ実装は2つの言語間で実装を共有でき、CとC++の相互運用性を高める事ができます。
// マルチスレッド対応していないライブラリのヘッダにおいて、それを警告するのに使用する // シングルスレッドで使用する分には問題ないのでコンパイルを止めたくない #warning This library currently has no thread support. ...
P2438R0 std::string::substr() &&
右辺値std::string
からのsubstr()
を効率化する提案。
std::string::substr()
関数は、元の文字列の一部を切り出した部分文字列を返す関数です。その際、切り出した部分文字列は新しいstd::string
オブジェクトにコピーされて返されます。
// コマンドライン引数の一部を取り出す benchmark = std::string(argv[i]).substr(12); // prvalueなstringの一部を切り出す name_ = obs.stringValue().substr(0,32);
このように、元のstd::string
オブジェクトが右辺値である場合、substr()
の処理では元の文字列の保持する領域を再利用してやることで余計なコピーとアロケーションを回避できます。これは、メンバ関数の&&
修飾を利用すれば可能であり、似たような最適化はstd::optional
などに見ることができます。
現在、std::string::substr()
にはconst
修飾されたものだけが提供されており、この提案ではそれを&&, const &
の2つに変更することを提案しています。
// 現在のsubstr() constexpr basic_string substr(size_type pos = 0, size_type n = npos) const; // この提案後のsubstr() constexpr basic_string substr(size_type pos = 0, size_type n = npos) const &; constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&;
提案より、振る舞いの変化例
// aから部分文字列のstringをコピーして作成、aは変更されない(この振る舞いは変わらない) auto a = std::string(/* */); auto b = a.substr(/* */); auto foo() -> std::string; // 現在 : 一時オブジェクトのstringから部分文字列のstringをコピーして作成 // 提案 : 一時オブジェクトのstringのリソースを再利用して部分文字列を保持するstringオブジェクトを作成 auto b = foo().substr(/* */); // 現在 : 一時オブジェクトのstringから部分文字列のstringをコピーして作成 // 提案 : 一時オブジェクトのstringのリソースを再利用して部分文字列を保持するstringオブジェクトを作成 auto a = std::string(/* */).substr(/* */); // 現在 : aから部分文字列のstringをコピーして作成、aは変更されない // 提案 : aのリソースを再利用して部分文字列を保持するstringオブジェクトを作成、aは有効だが未規定な状態となる auto a = std::string(/* */); auto b = std::move(a).substr(/* */);
最後のケースだけはこの提案の変更によって破壊的変更となります。とはいえ現在このように記述するメリットはないためこう書くことはなく、書いたとしても明示的にmove
しているためa
の値にはもはや関心が無いことを理解した上でコンパイラにそれを伝えているはずなので、この提案の変更によってその意図した振る舞いが得られることになります。
また、この変更は既存のsubstr() const
をcosnt &
と&&
に置き換えるものなのでABiの破壊も伴います。しかし、ライブラリ実装は古い実装を同時に提供し続けておくことができるため、ABIの後方互換を保ちながらこの変更を適用可能であるようです。
また、std::string
はコンストラクタによってもsubstr()
を使用したのと同じことを行うことができるようになっているため、この提案では同時に右辺値substr()
オーバーロードに対応したコンストラクタを追加することも提案しています。
// 右辺値stringから部分文字列を切り出すコンストラクタ constexpr basic_string( basic_string&& other, size_type pos, const Allocator& alloc = Allocator() ); constexpr basic_string( basic_string&& other, size_type pos, size_type count, const Allocator& alloc = Allocator() );
この提案のオーバーロードは、元のstd::string
オブジェクトのリソースを再利用することから、アロケータを適切に伝播しなければなりません。
std::pmr::string s1 = ....; std::pmr::string s2 = std::move(s1).substr();
この場合、s1.get_allocator() == s2.get_allocator()
とならないと、再利用したリソースを適切に開放することができません。これは、std::allocator_traits<A>::is_always_equal::value == true
となる場合は常に再利用することができます。そうならない状態を持つアロケータでもそれを再利用(move
)することで効率的なアロケータ伝播を達成できます。それ以外の場合(アロケータのムーブができないなど)は既存のsubstr()
と同じ振る舞いとなるため、効率性はなくなりますが追加のオーバーヘッドはありません。
この提案はこれらの最適化を実装に強制するものではなくこのような最適化を実装が選択できるようにし、またそれを推奨するものであり、実装はどのように最適化するかを自由に選択することができます。従って、このアロケータの伝播をどのようにするかは実装定義とすることを提案しています。
P2439R0 Slides for P2415R1, what is a view?
P2415R1の解説スライド。
view
コンセプトの変遷と、view
コンセプトが保証し表現するものは何か、そして提案(P2415)の目的についてまとめられています。
P2440R0 ranges::iota, ranges::shift_left, and ranges::shift_right
Rangeアルゴリズム、ranges::iota, ranges::shift_left, ranges::shift_right
の提案。
これらのアルゴリズムは新しいものではなく標準ライブラリに古いタイプのものが既にありますが、C++20ではrange
対応されていませんでした。
ranges::iota
ranges::iota
は効果が単純であるためすぐに追加できたのですが、<ranges>
にはすでにviews::iota
が存在しており、その有用性が不明であったためC++20には追加されませんでした。
しかし、ranges::iota
は出力範囲の要素数に基づいて書き込む値の数が決定されますが、views::iota
はそうではなくその数を事前に決定する必要があるため、ranges::iota
は出力範囲があらかじめ得られている場合に効率的です。
追加されるのは次の二つの形式のオーバーロードです。
// in <numeric> namespace std::ranges { // iotaの戻り値型 template<class O, class T> using iota_result = out_value_result<O, T>; // イテレータペアを受け取る template<input_or_output_iterator O, sentinel_for<O> S, weakly_incrementable T> requires indirectly_writable<O, const T&> constexpr iota_result<O, T> iota(O first, S last, T value); // Rangeオブジェクトを受け取る template<weakly_incrementable T, output_range<const T&> R> constexpr iota_result<borrowed_iterator_t<R>, T> iota(R&& r, T value); }
戻り値型であるiota_result
は範囲の終了位置を指すイテレータと計算値の最終値のペアとなる集成体です。
cpprefjpのサンプルを改変したコード例
#include <numeric> #include <iostream> #include <array> int main() { // 0から始まる10要素のシーケンスを作成する。 std::array<int, 10> ar; const auto [it, v] = std::ranges::iota(ar, 0); for (int x : ar) { std::cout << x << std::endl; // 0123456789 } std::cout << (it == ar.end()) << std::endl; // true std::cout << v; // 10 }
ranges::shift_left, ranges::shift_right
shift_left/shift_right
もC++20を目指していたのですが、ranges::shift_left
の戻り値型(シフト後範囲を示すranges::subrange
)が元の範囲の終端についての情報を失っている懸念から議論が長引き、C++20に間に合いませんでした。特に、番兵によって範囲の終端が示される場合、シフト後範囲の終端と番兵によって示される元の範囲の終端との間の要素はムーブされているため、元の範囲の終端を復元するのが難しいという懸念があったようです。
結局、次のような結論が得られたようです。
- 戻り値の
subrange
が空でない場合、そのend()
からシフト量n
だけ進めることで終端を回復できる。 - 戻り値の
subrange
が空の時(元の範囲のサイズよりシフト量の方が大きい時)、アルゴリズムは必ずしも元の範囲の終端を計算していない可能性がある。- この時必要なのはサイズのみ。それは
last - first
(引数のイテレータペアがsized_sentinel_for
のモデルとなる場合)かranges::size()
(引数のrange
型がsized_range
のモデルとなる場合)によって計算できる。 - そしてその場合、元の範囲は変更されないことが保証できる。
- この時必要なのはサイズのみ。それは
そして、ユーザーが自分で分解する必要のある複雑な型を返すよりも処理結果の部分範囲を示すsubrange
を返した方が使いやすく、範囲終端を計算する可能性があるがそれを返さないタイプのアルゴリズムには前例があります(ranges::cout, ranges::min/max
など)。そして、問題が発生しないranges::shift_rgiht
と戻り値型を一貫させることができます。
これらの理由からこの提案では、ranges::shift_left, ranges::shift_right
の戻り値型は当初の提案通りにシフト後の部分範囲を示すsubrange
とすることを提案しています。
提案ではranges::iota
と同様にそれぞれ2種のオーバーロードを追加します
namespace std::ranges { // イテレータペアを受け取るshift_left template<permutable I, sentinel_for<I> S> constexpr subrange<I> shift_left(I first, S last, iter_difference_t<I> n); // rangeオブジェクトを受け取るshift_left template<forward_range R> requires permutable<iterator_t<R>> constexpr borrowed_subrange_t<R> shift_left(R&& r, range_difference_t<R> n); // イテレータペアを受け取るshift_right template<permutable I, sentinel_for<I> S> constexpr subrange<I> shift_right(I first, S last, iter_difference_t<I> n); // rangeオブジェクトを受け取るshift_right template<forward_range R> requires permutable<iterator_t<R>> constexpr borrowed_subrange_t<R> shift_right(R&& r, range_difference_t<R> n); }
前述の議論の通り、戻り値型はシフト後のsubrange
です(borrowed_subrange_t
とは引数のrange
オブジェクトが右辺値であるなどダングリングイテレータの危険があるときに代わりのタグ型を返すものです)。
cpprefjpのサンプルを改変したコード例
#include <iostream> #include <ranges> #include <vector> #include <algorithm> int main() { // shift_left { std::vector<int> v = {1, 2, 3, 4, 5}; std::ranges::range auto shifted_range = std::ranges::shift_left(v, 2); for (int x : shifted_range) { std::cout << x << ','; // 3,4,5, } std::cout << std::endl; } // shift_right { std::vector<int> v = {1, 2, 3, 4, 5}; std::ranges::range auto shifted_range = std::ranges::shift_right(v, 2); for (int x : shifted_range) { std::cout << x << ','; // 1,2,3, } std::cout << std::endl; } }
P2441R0 views::join_with
パターンによってrange
のrange
となっているようなシーケンスを接合して平坦化するRangeアダプタ、views::join_with
の提案。
views::join
がrange
のrange
を単にそのまま平坦化(内側range
の各要素からなるrange
に変換)するのに対して、join_with
は指定されたパターンを挿入しながら平坦化します。
std::vector<std::string> vs = {"the", "quick", "brown", "fox"}; for (char c : vs | std::views::join_with(' ')) { cout << c; } // "the quick brown fox"という文字列が出力される for (char c : vs | std::views::join) { cout << c; } // "thequickbrownfox"という文字列が出力される
この例では入力のvs
はstd::string
のstd::vector
というrange
のrange
であり、内側のrange
はstd::striing
です。views::join
による平坦化は内側range
の各std::string
をそのまま繋げたrange
に変換するものですが、views::join_with
は内側の各range
の間に指定されたパターン(ここではスペース1つ)を挿入して1本のrange
に変換します。
また、これはviews::split
の逆変換となっており、パターンp
によるstr | views::split(p) | views::join_with(p)
の様な変換は、もとのstr
と同じシーケンスとなります(型は異なりますが)。
この様な平坦化は、views::join
が追加の引数を取るようにすることによっても実装できますが、range
のrange
をviews::join
Rangeアダプタオブジェクトに渡したときの曖昧さを回避するために別の名前のview
として導入しています(views::join(rr)
がrr
を平坦化したいのかrr
でjoin_with
したのか不明瞭になる)。
上記例では単に文字(single_view
に変換されている)を渡していましたがjoin_with
のパターンには任意のrange
を渡すことができ、そのvalue_type/reference
は入力range
の内側range
のvalue_type/reference
とcommon_type
を有している必要があり、そのcommon_type
がjoin_with
のvalue_type/reference
となります。
join_with
はjoin
と同様に入力としてprvalueの非view
なrange
をキャッシュすることで処理することができます。その場合のjoin_with
はinput_range
となり、そうでない場合は入力range
とその内側range
及びパターンのrange
の共通部分となるカテゴリになります。
P2442R0 Windowing range adaptors: views::chunk
and views::slide
元のシーケンスの各要素を指定した要素数のウィンドウによって参照するようなview
を生成する、views::chunk/views::slide
アダプタの提案。
提案文書より、サンプルコード。
std::vector v = {1, 2, 3, 4, 5}; fmt::print("{}\n", v | std::views::chunk(2)); // [[1, 2], [3, 4], [5]] fmt::print("{}\n", v | std::views::slide(2)); // [[1, 2], [2, 3], [3, 4], [4, 5]]
fmt::print
は任意のrange
の直接出力が可能で、1つの範囲を[]
で囲います。
この2つのview
はどちらも、range
のrange
を生成するものです。
views::chunk
views::chunk(R, N)
は入力範囲R
の各要素をN
個づつまとめた組を要素とするrange
を生成します。その際、サイズN
のウィンドウはR
上でオーバーラップせずにchunk
の各要素を生成します。R
の要素数がN
で割り切れない場合、chunk
の最後の要素のサイズはN
よりも小さくなります。
views::chunk
の各要素はviews::take
によって生成され、chunk
のvalue_type
(外側range
型)はviews::take(R, N)
の結果によります。その場合(入力range
がforward
より強い場合)、入力range
の諸性質をほぼそのまま受け継ぎます。
一方でviews::chunk
はinput_range
の入力をサポートする事が提案されています。その場合、元となるイテレータとその反復状態はchunk_view
自身によって管理され、入力range
の要素はキャッシュされます。したがってその場合は、const
-iterableではなくなるなど大きく性質が制限されます。
views::slide
views::slide(R, N)
は入力範囲R
の各要素をN
個づつまとめた組を要素とするrange
を生成しますが、views::chunk
と異なりサイズN
のウィンドウはR
上で1要素分オーバーラップしてchunk
の各要素を生成します。すなわち、slide
のM
番目の要素はR
のM
番目から(M+N-1)
番目の要素を参照します。
これはviews::adjacent
とよく似ていますが、こちらはウィンドウサイズN
を実行時に指定できる点で異なっています。
views::slide
の各要素はviews::counted
によって生成され、value_type
(外側range
型)はstd::span
かstd::ranges::subrange
のどちらかになります。その性質の多くは、入力となるrange
型から継承します。
views::slide
では、chunk
と異なりinput_range
をサポートしません。この場合の要素のキャッシュは複雑となりキャッシュしない場合との差が大きくなり、ユーザーの関心のある要素以外の要素も全てコピーして保持する必要があるなど、あらゆる側面から高コストとなってしまうためです。このことは、views::adjacent
で議論され決定されたことを引き継いています。
P2443R0 views::chunk_by
指定された述語によって元のシーケンスの可変個の要素を組にした要素からなるシーケンスを生成する、views::chunk_by
アダプタの提案。
std::vector v = {1, 2, 2, 3, 0, 4, 5, 2}; fmt::print("{}\n", v | std::views::chunk_by(ranges::less_equal{})); // [[1, 2, 2, 3], [0, 4, 5], [2]]
つまり、元のシーケンス上(例ではv
)で連続する2つの要素について、指定された述語(例ではranges::less_equal
、<=
比較)がfalse
となる所を区切りとしてchunk
を生成します。逆に言うと、述語がtrue
となる連続要素が1つの組としてchunk_by
の1要素になります。
これもrange
のrange
を生成するview
であり、views:chunk
の各要素がviews::take
で実装されるのに対してviews::take_while
によって生成されるものと見るとわかりやすいかもしれません(実際にはsubrange
によって生成されますが)。
views::slide
、views::adjacent
と同様の理由により、chunk_by
はinput_range
をサポートしません。chunk_by
自身はbidirectional_range
かforward_range
のどちらかとなり、入力range
がcommon_range
であるときにそれを継承しますが、sized_range, borrowed_range
にはなりません。
また、views::split
などと同様に、range
コンセプトの意味論要件を満たすために最初のbegin()
の呼び出し時にchunk_by
の最初の要素を導出するためのイテレータを計算してキャッシュしています。このため、const-iterable
ではなくなります。
P2444R0 The Asio asynchronous model
Asioライブラリの非同期処理モデルについて解説した文書。
Asioは基礎的なソケット通信を行うためのデファクト的なライブラリですが、ネットワーキングにつきものの並行処理についてのサポートも充実しています。
この文書は、Asioの作者の方自らAsioの非同期処理モデルの概要を紹介するものです。
どうやらこれは、NetworkingTSのベースとなっているAsioの非同期モデルについて周知するとともに、現在のExecutor提案によって導入されようとしている(Networking TSの下地となる)非同期モデルとの相互運用性について議論するためのもののようです。
P2446R0 views::move
入力シーケンスの各要素をstd::move
するようなview
である、views::move
の提案
std::vector<string> words = {"the", "quick", "brown", "fox", "ate", "a", "pterodactyl"}; std::vector<string> new_words; // wordsのstringをnew_wordsへムーブする std::ranges::copy(words | views::move, std::back_inserter(new_words));
views::move
はviews::transfom(std::move)
とほぼ同等のものです。しかし実際には、std::move
が関数テンプレートである事からそのような渡し方はできません。
また、views::transfom(std::move)
の入力となるrange
のreference
がprvalueであった場合、std::move
することは無駄にprvalueの実体化を行うことになるため、効率的ではなくなる可能性があります。そのため、正確にそれを行うには入力range
のreference
がlvalueの時だけstd::move
する必要があります。それはイテレータに対してstd::ranges::iter_move
CPOが行なっている事ですが、iter_move
はイテレータそのものに対して作用するため、こちらもそのままtransform
に渡すことができません。
Range-v3にはrange
のイテレータに対して変換を行うiter_transform
があります。しかし、そちらはムーブに特化したものではなくより汎用なものであり、入力のrange
の性質をより良く反映してしまいます。すなわち、views::move
によって生成されるrange
はinput_range
でなければなりません。これはviews::transfom(std::move)
にも言えることです。
そして、views::move
はranges::to
によってrange
からコンテナへの変換をより効率的に行うのに大いに役立ちます。さらに、move_iterator
がすでに存在しているため、ムーブオンリーイテレータの設計について時間をかけずともすぐに実装することができます(実際に、提案ではmove_iterator
を使用して実装しています)。
これらの理由から、views::move
はファーストクラスのRangeアダプタとしてふさわしいものであるので、標準に追加しようとする提案です。
std::vector<string> words = {"the", "quick", "brown", "fox", "ate", "a", "pterodactyl"}; // そのままだとコピーになる auto copy_vec = words | ranges::to<std::vector>; // views::moveを適用することで適切にムーブできる auto move_vec = words | views::move | ranges::to<std::vector>;