文書の一覧
全部で27本あります(SG22のWG14からのものは除きます)。
- N4908 Working Draft, C++ Extensions for Library Fundamentals, Version 3
- N4909 Editor's Report: C++ Extensions for Library Fundamentals, Version 3
- N4910 Working Draft, Standard for Programming Language C++
- N4911 Editors’ Report - Programming Languages - C++
- P0009R16 MDSPAN
- P0957R6 Proxy: A Polymorphic Programming Library
- P1083R5 Move resource_adaptor from Library TS to the C++ WP
- P1684R1 mdarray: An Owning Multidimensional Array Analog of mdspan
- P1708R6 Simple Statistical Functions
- P1839R4 Accessing Object Representations
- P2264R3 Make assert() macro user friendly for C and C++
- P2290R3 Delimited escape sequences
- P2465R3 Standard Library Modules std and std.compat
- P2510R1 Formatting pointers
- P2511R1 Beyond operator(): NTTP callables in type-erased call wrappers
- P2521R2 Contract support - Working Paper
- P2539R0 Should the output of std::print to a terminal be synchronized with the underlying stream?
- P2540R1 Empty Product for certain Views
- P2553R1 Make mdspan size_type controllable
- P2555R1 Naming improvements for std::execution
- P2558R0 Add @, $, and ` to the basic character set
- P2560R0 Comparing value- and type-based reflection
- P2562R0 constexpr Stable Sorting
- P2564R0 consteval needs to propagate up
- P2565R0 Supporting User-Defined Attributes
- P2568R0 Proposal of std::map::at_ptr
- P2569R0 *_HAS_SUBNORM==0 implies what?
- おわり
N4908 Working Draft, C++ Extensions for Library Fundamentals, Version 3
次期標準ライブラリ機能候補の実装経験を得るためのTSである、Library Fundamental TS v3の文書。
N4909 Editor's Report: C++ Extensions for Library Fundamentals, Version 3
↑の変更点を記した文書。
この版での変更は、LWG Issue 3649を反映したことです。
N4910 Working Draft, Standard for Programming Language C++
N4911 Editors’ Report - Programming Languages - C++
↑の変更点をまとめた文書。
2月の会議で採択された提案とコア言語/ライブラリのIssue解決が適用されています。
P0009R16 MDSPAN
多次元配列に対するstd::span
である、mdspan
の提案。
以前の記事を参照
- P0009R12 MDSPAN - WG21月次提案文書を眺める(2021年05月)
- P0009R13 MDSPAN - WG21月次提案文書を眺める(2021年10月)
- P0009R14 MDSPAN - WG21月次提案文書を眺める(2021年11月)
- P0009R15 MDSPAN - WG21月次提案文書を眺める(2022年02月)
このリビジョンでの変更は、LWGのフィードバックを受けての文言の修正です。
P0957R6 Proxy: A Polymorphic Programming Library
静的な多態的プログラミングのためのユーティリティ、"Proxy"の提案。
以前の記事を参照
このリビジョンでの変更は、ODR違反防止のためにstd::dispatch
宣言の構文を再設計したこと、それに伴って、std::dispatch
関連の文言を修正したことです。
以前の提案では、std::dispatch
はテンプレート引数として1つめに関数型、2つめにそれに合うCallable(ディスパッチ処理)をNTTPで受けていました。このリビジョンでは、2つめのパラメータを無くして、std::dispatch
の実装クラスのメンバ関数(operator()
)としてディスパッチ処理を記述するようにしました。
// 以前の提案 struct Draw : std::dispatch< void(), [](const auto& self) { self.Draw(); }> {}; struct Area : std::dispatch< double(), [](const auto& self) { return self.Area(); }> {}; // この提案 struct Draw : std::dispatch<void()> { template <class T> void operator()(const T& self) { return self.Draw(); } }; struct Area : std::dispatch<double()> { template <class T> double operator()(const T& self) { return self.Area(); } };
ラムダ式がNTTPに渡されている時でもそのクロージャ型は宣言ごとに固有の型をもつため、ヘッダに宣言されたstd::dispatch
の特殊化を複数の翻訳単位から参照するとODR違反を起こします。この変更はおそらくこれを防止するためのものです。
/// foo.h template <auto> struct foo { }; // 2つ以上の翻訳単位から参照されると未定義動作(ODR違反) extern foo<+[]() {}> x; inline foo<+[]() {}> y; /// tu1.cpp #include "foo.h" /// tu2.cpp #include "foo.h"
P1083R5 Move resource_adaptor from Library TS to the C++ WP
pmr::resource_adaptor
をLibrary Foundermental TSからワーキングドラフトへ移動する提案。
以前の記事を参照
このリビジョンでの変更は、aligned_object_storage<T>
のT
はオブジェクト型でなければならないことを規定したこと、aligned_object_storage<T>
のT
がCV修飾される可能性を考慮するようにしたこと、Library Foundermental TSの参照をv2からv3へ更新したことです。
この提案はLEWGのレビューをひとまず終えて、LWGに送られるための投票待ちをしています。
P1684R1 mdarray
: An Owning Multidimensional Array Analog of mdspan
多次元配列クラスmdarray
の提案。
std::mdspan
(P0009)は別に確保された領域を適切に参照することで、所有権を保持せずに多次元配列を使用するものです。ユースケースによっては(小さい固定サイズの配列を使用する場合など)、多次元配列を所有した状態で同様に使用したい場合があります。それによって、std::mdspan
では回避できない間接参照のコストを削減でき、サイズが小さい場合は参照局所性の向上や最適化によるレジスタへの配置などを期待できます。この提案のmdarray
はその目的のための多次元配列クラスです。
// mdspanを使用する場合 void make_random_rotation(mdspan<float, std::extents<3, 3>> output); void apply_rotation(mdspan<float, std::extents<3, 3>>, mdspan<float, 3>); void random_rotate(mdspan<float, std::extents<dynamic_extent, 3>> points) { float buffer[9] = { }; auto rotation = mdspan<float, 3, 3>(buffer); make_random_rotation(rotation); for(int i = 0; i < points.extent(0); ++i) { apply_rotation(rotation, subspan(points, i, std::all)); } }
// mdarrayを使用する場合 mdarray<float, std::extents<3, 3>> make_random_rotation(); void apply_rotation(mdarray<float, std::extents<3, 3>>&, const mdspan<float, std::extents<3>>&); void random_rotate(mdspan<float, std::extents<dynamic_extent, 3>> points) { auto rotation = make_random_rotation(); for(int i = 0; i < points.extent(0); ++i) { apply_rotation(rotation, subspan(points, i, std::all)); } }
この提案によるmdarray
は、mdspan
とそれが参照するメモリ領域(を保持するコンテナ)を1つのクラスにまとめたような設計になっています。特に、そのインターフェースはmdspan
と共通しており、mdspan
の利用に慣れたユーザーがほぼそのままmdarray
を利用できるようになっています。
// mdarrayのクラス定義の一部例 template<class ElementType, class Extents, class LayoutPolicy = layout_right, class Container = ...> class mdarray { ... using mapping_type = typename layout_type::template mapping<Extents>; ... private: container_type ctr_; mapping_type map_; };
mdarray
はその内部領域を保持するコンテナ型を一番最後のテンプレートパラメータで変更することができます。デフォルトでは、Extents
の一部がdynamic_extent
であればstd::vector<ElementType>
、Extents
が全て静的であればstd::array<ElementType, N>
(N
はExtents
の値の積)となります。手動で指定する場合、Container
はcontiguous container要件を満たしている必要があります。
LayoutPolicy
のデフォルトは、1次元の配列を多次元配列として(行優先で)アクセスするときのインデックス変換を行うものです。その変更は、たとえばその要素へのアクセスにアトミックアクセスが必要である場合などに使用することができます。
ただし、mdarray
は配列を所有するものであるため、mdspan
とは異なりコンテナセマンティクスを持ちます。特に、mdarray
はdeep constnessを持っており、mdarray
事態のconst
性は(そのconst
メンバ関数を通して)各要素まで伝播されます。これはmdspan
とは異なり、std::vector
などとのコンテナと共通する性質です。
P1708R6 Simple Statistical Functions
標準ライブラリにいくつかの統計関数を追加する提案。
以前の記事を参照
- P1708R3 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2021年01月)
- P1708R4 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2021年04月)
- P1708R5 Simple Statistical Functions - [C++]WG21月次提案文書を眺める(2021年06月)
このリビジョンでの変更は
stats_result_t
の削除- Accumulator objectを並列実装が可能となるように改善
stat_accum
とweighted_stat_accum
の削除- より多くのデータ型を許可するために一部の制約を緩和
- Projectionの削除(必要なら、
views::transform
によって行えるため) - 多くの名前に変更
などです。
P1839R4 Accessing Object Representations
reinterpret_cast<char*>
によるオブジェクト表現へのアクセスを未定義動作とならないようにする提案。
以前の記事を参照
このリビジョンでの変更は、提案する文言内のオブジェクト表現のN
について曖昧な使用を修正したことです。
P2264R3 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月)
このリビジョンでの変更は、
などです。
WG14は、C23に向けてこの提案を採択しています。C++に向けてはC++26を目指して作業しています。
P2290R3 Delimited escape sequences
文字・文字列定数中の8進・16進エスケープシーケンスおよびユニバーサル文字名について、その区切りが明確になるような形式を追加する提案。
前回の記事を参照
- P2290R0 Delimited escape sequences - [C++]WG21月次提案文書を眺める(2021年02月)
- P2290R1 Delimited escape sequences - [C++]WG21月次提案文書を眺める(2021年06月)
- P2290R2 Delimited escape sequences - [C++]WG21月次提案文書を眺める(2021年07月)
このリビジョンでの変更は、conditional-escape sequenceのリストから\o
を取り除いたことです。
この提案はCWG/EWGでのレビューを終えており、次の全体会議で投票にかけられる予定です。
P2465R3 Standard Library Modules std and std.compat
標準ライブラリモジュールについて最小のサポートをC++23に追加する提案
以前の記事を参照
- P2465R1 Standard Library Modules
std
andstd.compat
- WG21月次提案文書を眺める(2021年10月) - P2465R2 Standard Library Modules
std
andstd.compat
- WG21月次提案文書を眺める(2022年02月)
このリビジョンでの変更は、CWGのフィードバックを受けての文言の修正です。
この提案はすでにLWG/CWGでのレビューを終えており、次の全体会議で投票にかけられることが決まっています。
P2510R1 Formatting pointers
std::format
について、ポインタ型のフォーマットを充実させる提案。
以前の記事を参照
このリビジョンでの変更は、LEWGのフィードバックを受けての文言の修正です。
P2511R1 Beyond operator()
: NTTP callables in type-erased call wrappers
std::move_only_fuction
を、呼び出し可能なNTTP値を型消去するCallable Wrapperへ拡張する提案。
以前の記事を参照
このリビジョンでの変更は、寄せられたコメントへの返答、std::function
のための文言を追加した事などです。
このリビジョンでは、std::function
に対してもnontype_t
からの構築を行うコンストラクタが追加されました。
P2521R2 Contract support - Working Paper
以前の記事を参照
このリビジョンでの変更は、
- 事前条件と事後条件の評価順序について提案を追加
- 引数初期化 -> 事前条件評価 -> 関数本体の評価 -> ローカル変数のデストラクタ実行 -> 事後条件評価、の順を提案
- 事後条件で使用される非参照の関数引数は
const
でなければならない、とした - 関数の仮引数の代わりに、関数の実引数の値を事後条件で使用したとしても、事後条件で非参照引数を利用する際の問題を解決できないことに関する説明を追記
- 副作用の除去を提案する動機を更新
などです。
P2539R0 Should the output of std::print
to a terminal be synchronized with the underlying stream?
提案中のstd::print
(P2093)が出力するストリームについて、同じストリームに対する他の出力との同期を取るべきという意見についての報告書。
std::print
(及びfmt::print
)では、文字化け防止のためにコンソール出力時にストリームバッファをバイパスして書き込んでおり、その際に環境ネイティブのユニコードAPIを使用する場合があります。
P2093のレビューでは、std::print
をその基礎となるストリーム(出力先ストリーム、デフォルトではstdout
)と同期させることが移行のために有益だろうという意見が出たようです。この文書は、その提案についての報告書です。
printf("first\n"); std::print("second\n");
この単純なコードは、次のように出力されることが期待されます。
first second
しかし実際には、この順番は入れ替わる可能性があります。なぜなら、printf
はバッファリングするのに対して、std::print
はそれを行わないためです。
これを期待通りに出力するためには、std::print
が書き込み動作をする前にストリームバッファをflushする必要があります。ただし、それをすると小さくない追加のコストがかかります。そして、{fmt}
でもRustのコンソール出力でも、現在そのような同期は行われていません。
この文書は何かを提案するものではなく、問題の周知や別の解決策・対案を得るためのものです。
P2540R1 Empty Product for certain Views
view
の空積は空のタプルになるべきという提案。
以前の記事を参照
このリビジョンでの変更は、提案する文言を追加したことです(多分)。
この提案はLEWGのレビューをひとまず終えて、LWGに送られるための投票待ちをしています。
P2553R1 Make mdspan size_type
controllable
P0009で提案中のstd::mdspan
について、そのsize_type
を制御可能とする提案。
以前の記事を参照
このリビジョンでの変更は、size_type
を符号付き整数型に制限しないようにしたこと、それに伴ってextents
のコンストラクタに事前条件(0以上の値であること)を追加したこと、size_type
の変換が縮小変換となる場合にexplicit
になるようにしたことなどです。
この提案はLEWGのレビューをひとまず終えて、LWGに送られるための投票待ちをしています。
P2555R1 Naming improvements for std::execution
P2300で提案されている、sender
ファクトリ及びsender
アダプタの一部のものについて、名前を改善する提案。
以前の記事を参照
このリビジョンでの変更は、文字化けを修正したことです。
P2558R0 Add @, $, and ` to the basic character set
@ $ `の3種類の文字をソースコードの基本文字集合に追加する提案。
これらの文字はAsciiに含まれているものですが、ソースコードの基本文字集合(basic character set)には含まれていませんでした。基本文字集合はC/C++の基本的な文法を記述するために使用される文字の集合であり、そこに追加しておけば将来的な構文拡張の際に使用可能となります。
この3つの文字は、C++では基本文字集合にこそ含まれていなかったものの、1バイト文字として翻訳文字集合(Translation character set、ソースコードを記述するのに使用可能な文字の集合。C++23で導入された概念)には含まれていました。Cには翻訳文字集合の概念はなく、この3つは基本文字集合に含まれていませんでしたが、C23でこの3つはCの基本文字集合に追加されました。CはC++よりさらに保守的(後方互換に敏感)ですが、この3つの文字の将来的な利用に障害がないことを確認した上で基本文字集合に追加しています。
C++ではCほどの重要性はないものの、将来的な構文のために使用可能にしておくことは有益であるとして、C23での決定を踏襲してC++でも@ $ `を基本文字集合へ追加しておこうとする提案です。
- N2701: @ and $ in source and execution character set
- Character sets and encodings - cppreference
- P2342R0 For a Few Punctuators More - WG21月次提案文書を眺める(2021年04月)
- P2558 進行状況
P2560R0 Comparing value- and type-based reflection
値ベースのリフレクションと型ベースのリフレクションの比較スライド。
現在のリフレクション機能の候補には型ベースのものと値ベースの2種類があります。型ベースはリフレクションの結果(メタオブジェクト、メタ情報を格納するもの)が型で得られるのに対して、値ベースはリフレクションの結果が値(コンパイル時の値)で得られます。型ベースはTMPとの親和性に、値ベースはconstexpr
処理との親和性に優れています。
Reflection TSは現在型ベースのリフレクションで設計されていますが、リフレクションの方向性としては値ベースのものにしていこうとしているようです。
このスライドはその両者を比較するもので、ユーザビリティでは型ベースが優れており、コンパイル時間への影響は値ベースの方が小さいことを報告しています。その結論としては、値ベースリフレクションにはコンパイル時間の利点しかなく、それだけを重視して値ベースのリフレクションを採用するのか?という疑問を投げかけています。
P2562R0 constexpr Stable Sorting
std::stable_sort
とそのファミリをconstexpr
対応する提案。
この提案の対象は次のものです。
std::stable_sort
std::stable_partition
std::inplace merge
- これらの
ranges
版
これらのものはどれも安定ソート(同値なものの相対順序が保たれるソート)によって並べ替えやマージを行うものですが、ranges
のものも含めてどれもconstexpr
ではありません。その原因は、入力範囲の長さによって追加のメモリ領域を使用するかしないかを動的に分岐する実装になっているためです。
このことは規格によっても指定されていて、例えばstd::stable_sort
なら「計算量はN log2(N)(回の比較)、ただし追加のメモリが使用できる場合はN log N」のように規定されています。追加のメモリが使用できる場合がいつなのかは指定されていませんが、実装は入力範囲が一定の長さを超える場合にその場でメモリを確保して使用します。
この追加のストレージを使用する経路が、stable_sort
とそのファミリのconstexpr
対応を妨げていたようです。ただし、追加のメモリを使用しない経路の実装は現在でもconstexpr
対応が可能であり、こちらの経路はそのままconstexpr
指定することができます。
このような実行経路による定数実行可能性の問題は、std::is_constant_evaluated()
によって解決されます。これによって、定数式で実行可能なパスの選択を静的に行うことができるため、std::stable_sort
とそのファミリをconstexpr
対応させることができます。
また、C++20からは動的メモリ確保が定数式で行えるようになり、std::vector
を定数式で使用可能となります。C++23からは同様にstd::unique_ptr
も定数式で使用可能となるため、これらを用いた実装ならばすべてのパスでconstexpr
対応させることが可能です。
P2564R0 consteval
needs to propagate up
consteval
関数をconstexpr
関数の中で呼び出すことができない問題を軽減する提案。
値ベースのリフレクション(P1240)では、std::meta::info
という単一の型によってリフレクションの結果を表現することが提案されています。そして、多くのところではstd::meta::info
のシーケンス(std::vector<std::meta::info>
など)を扱うことになることが予想されます。すると、自然に既存のアルゴリズム(<algorithm>
)を使用したくなります。
namespace std::meta { // std::meta::infoの仮の実装とする struct info { int value; }; // std::meta::infoがある条件を満たしているかを調べる関数の一例 consteval auto is_invalid(info i) -> bool { // 偶数を許可しない return i.value % 2 == 0; } } // std::meta::infoのシーケンス constexpr std::meta::info types[] = {1, 3, 5};
std::meta::info
の実装は現在ないので、このような仮想的な実装で実験をしてみます(ここでの問題にはこれで十分です)。ここで注意するのは、std::meta::is_invalid()
はconsteval
関数であることです。
// NG // is_invalid()の呼出(none_of内)は即時関数コンテキストではない static_assert(std::ranges::none_of( types, std::meta::is_invalid )); // NG static_assert(std::ranges::none_of( types, [](std::meta::info i) { return std::meta::is_invalid(i); // is_invalid()の呼出は即時呼出となるが、iが定数式ではないためNG } )); // NG // is_invalid()をラップするラムダの呼出(none_of内)は即時関数コンテキストではない static_assert(std::ranges::none_of( types, [](std::meta::info i) consteval { return std::meta::is_invalid(i); } )); // NG // 即時関数コンテキストではないところで、consteval関数の関数ポインタを取れない static_assert(std::ranges::none_of( types, +[](std::meta::info i) consteval { return std::meta::is_invalid(i); } ));
次に、アルゴリズム(ここではnone_of
)の結果を直接static_assert
に渡す代わりに、consteval
関数の内部で使用してみます。
// OK(ただし言語ルール的には) // 標準ライブラリのルールでは、規定されていない限りそのアドレスをとることができない consteval auto all_valid() -> bool { return std::ranges::none_of( types, std::meta::is_invalid ); } static_assert(all_valid()); // NG consteval auto all_valid() -> bool { return std::ranges::none_of( types, [](std::meta::info i) { return std::meta::is_invalid(i); // iは定数式ではない } ); } static_assert(all_valid()); // NG // is_invalid()をラップするラムダの呼出(none_of内)は即時関数コンテキストではない consteval auto all_valid() -> bool { return std::ranges::none_of( types, [](std::meta::info i) consteval { return std::meta::is_invalid(i); } ); } static_assert(all_valid()); // OK consteval auto all_valid() -> bool { return std::ranges::none_of( types, +[](std::meta::info i) consteval { return std::meta::is_invalid(i); } ); } static_assert(all_valid());
一番最後の方法(consteval
関数の中で、consteval
関数をconsteval
ラムダでラップして、関数ポインタを取得する)だけが、完全に合法的にconsteval
関数を既存のアルゴリズムで使用する方法です。
この問題の原因は、consteval
関数を呼び出すことができるのは即時関数コンテキスト(immediate function context)と呼ばれる文脈の中だけであることから起きています。特に、他の関数内でconsteval
関数を呼び出そうとすると、その関数もまたconsteval
でなければなりません。そうするとconsteval
関数は呼び出せなくなる気がしますが、呼出が完全に定数式であれば(引数が定数式であれば)どこの関数内でも呼び出すことができ、その場合のことを即時呼出(immediate invocation)と言います。
consteval f(int i) { return i; } constexpr void g(int i) { // g()の内部は即時関数コンテキストではない f(0); // ok、即時呼出 f(i); // ng、iは定数式ではない } consteval void h(int i) { // h()の内部は即時関数コンテキスト f(0); // ok f(i); // ok }
std::ranges::none_of
をはじめとする標準アルゴリズムは、constexpr
指定されているものはあってもconsteval
指定されているものはありません。そのため、関数を受け取って何かをするアルゴリズムの場合、その内部が即時関数コンテキストではないことからconsteval
関数を受け取って実行することができません。
これと同様の問題はstd::is_constant_evaluated()
でも問題となっていて、C++23ではその解決のためにif consteval
が導入されました(P1938R3)。if consteval
はtrue
ブロック(定数式で実行されるべきブロック)を即時関数コンテキストとすることで、定数式でしか実行されないtrue
ブロックにおいてconsteval
関数を自然に呼び出せるようにします。これを利用すると、この問題の解決を図れそうです。
// OK static_assert(std::ranges::none_of( types, [](std::meta::info i) { if consteval { return std::meta::is_invalid(i); // ここは即時関数コンテキスト } })); // NG // none_of内は即時関数コンテキストではない static_assert(std::ranges::none_of( types, [](std::meta::info i) consteval { if consteval { return std::meta::is_invalid(i); } }));
それでもなお、アルゴリズムが直接呼び出す関数はconsteval
であってはいけません。そのため、非consteval
ラムダによるラップが必要です。根本的な解決を図るには、ライブラリ関数の変更が必要です。
template <ranges::input_range R, class Pred> constexpr auto my::none_of(R&& r, Pred pred) -> bool { auto first = ranges::begin(r); auto last = ranges::end(r); for (; first != last; ++first) { if consteval { // 即時関数コンテキスト if (pred(*first)) { return false; } } else { // 即時関数コンテキストではない if (pred(*first)) { return false; } } } return true; }
if consteval
の半目的外使用に目を瞑れば、このような変更でそのままpred
にconsteval
関数を渡せるような気がします。ただしこれは実際には機能しません。なぜなら、pred
がconsteval
関数の場合、if consteval
のfalse
ブロックで結局同じ問題が発生するからです。
ライブラリ側で解決を図るには、もっと大元でif consteval
で分岐しておくことで、定数式(即時関数)用の処理と実行時処理を分岐する必要があります。そして、その分岐先の処理(コード)は全く同じになるでしょう。しかし統一することはできません・・・
無論そのような醜い解決策は解決とはいえないため、この問題の解決には言語レベルでの対処が必要となります。
問題を単純化してみてみると
constexpr auto pred_bad(std::meta::info i) -> bool { return std::meta::is_invalid(i); // NG、即時関数コンテキストではない } constexpr auto pred_good(std::meta::info i) -> bool { if consteval { return std::meta::is_invalid(i); // OK、即時関数コンテキスト } // UB、実行時にリターンしない }
pred_bad()
は今日ではNGであり、consteval
関数が確実にコンパイル時にのみ呼ばれるという性質を保証する1つの方法の結果です。pred_good()
はconsteval
関数の呼出がif consteval
のブロック(即時関数コンテキスト)にのみ現れているため、問題ありません。ここで、pred_good()
はconstexpr
とマークされていますが、実際には定数式でのみ呼び出すことができます(何もリターンしないため実行時にはUB)。従って、これも優れた解決策であるとはいえません。
pred_good()
をコンパイル時にのみ呼出可能なようにすることができれば問題は解決しますが、それは結局consteval
関数に行き付き堂々巡りになります。
最良の方法はどうやら、pred_bad()
が実行時に呼び出されないことを保証すればよさそうです。pred_bad()
の問題点はconsteval
関数が確実に呼ばれるのにconstexpr
関数であることから実行時にも呼び出すことができうる点にあります。したがって、pred_bad()
の呼出がコンパイル時にのみ行われることを保証できれば、pred_bad()
がNGである必要は無くなります。
この提案は、constexpr
関数がコンパイル時にのみ呼出可能である場合に、それらの関数を暗黙consteval
関数とすることで上記の問題の解決を図るものです。そのために、次のようなルールを提案しています
constexpr
関数が即時関数コンテキスト外のconsteval
関数呼出を含み、その呼出が定数式ではない場合、そのconstexpr
関数は暗黙的にconsteval
関数となる。- 式が、1と同様のコンテキストで即時呼出ではない
consteval
関数を呼び出す場合、そのコンテキストも暗黙的にそのコンテキストも暗黙的にconsteval
関数(即時関数コンテキスト)となる。 - manifestly constant evaluatedコンテキスト(
std::is_constant_evalueted()
がtrue
となるコンテキスト)は即時関数コンテキストと見做される。
これらの変更によって、先ほどNGだったstd::meta::info
のシーケンスに対する標準アルゴリズムの呼出は、全てコンパイルが通り、(直接渡すものもラムダによるものも)意図通りに実行されるようになります。
P2565R0 Supporting User-Defined Attributes
ユーザー/ベンダー定義の属性について、全てのコンパイラでサポートされる(警告が出ない)属性構文の提案。
C++標準では、「規格で指定されていない属性は実装(コンパイラ)によってサポートされ、実装が認識できない属性については無視される」のように規定されており、非標準の属性をサポートしています。コンパイラは別のベンダーやユーザー定義の属性については無視することでサポートすべきですが、現在主要なコンパイラは属性名のタイプミス検出のために不明な属性について警告を発します。
// deprecatedのタイプミス [[ edprecated("Broken. Use `bravo`.") ]] double banana(double num);
// Clang 13.0.1 <source>:6:4: warning: unknown attribute 'edprecated' ignored [-Wunknown-attributes] [[ edprecated("Broken. Use `bravo`.") ]] ^~~~~~~~~~ // GCC 11.2 <source>:7:25: warning: 'edprecated' attribute directive ignored [-Wattributes] 7 | double banana(double num); | // MSVC v19.30 <source>(6): warning C5030: attribute 'edprecated' is not recognized
これはユーザー定義属性(何かしらの手段で実装したとする)に対しても同様です。
// deprecated属性の拡張、2つ目の引数に重要度を受け取る [[ bespoke::deprecated("Broken. Use `charlie`.", "warn") ]] double carrot(double num);
// Clang 13.0.1 <source>:9:4: warning: unknown attribute 'deprecated' ignored [-Wunknown-attributes] [[ bespoke::deprecated("Broken. Use `charlie`.", "warn") ]] ^~~~~~~~~~~~~~~~~~~> // GCC 11.2 <source>:10:25: warning: 'bespoke::deprecated' scoped attribute directive ignored [-Wattributes] 10 | double carrot(double num); | // MSVC v19.30 <source>(9): warning C5030: attribute 'bespoke::deprecated' is not recognized
そして、ベンダー定義属性についても、各コンパイラが互いに同様の報告をします。
[[ clang::no_sanitize("undefined") ]] [[ gnu::access(read_only, 1) ]] [[ msvc::known_semantics ]] double daikon(double num);
// Clang 13.0.1 <source>:13:4: warning: unknown attribute 'access' ignored [-Wunknown-attributes] [[ gnu::access(read_only, 1) ]] ^~~~~~~~~~~ <source>:14:4: warning: unknown attribute 'known_semantics' ignored [-Wunknown-attributes] [[ msvc::known_semantics ]] ^~~~~~~~~~~~~~~~~~~~~ // GCC 11.2 <source>:15:21: warning: 'clang::no_sanitize' scoped attribute directive ignored [-Wattributes] 15 | int* daikon(int* num); | ^ <source>:15:21: warning: 'msvc::known_semantics' scoped attribute directive ignored [-Wattributes] Compiler returned: 0 // MSVC v19.30 <source>(12): warning C5030: attribute 'clang::no_sanitize' is not recognized <source>(13): warning C5030: attribute 'gnu::access' is not recognized
このことは、ベンダー定義であってもユーザー定義であっても、非標準の属性は実質的にサポート(警告もない完全な無視)されていないことを意味しています。この問題の回避のために、規模の大きなプロジェクトやライブラリでは、プリプロセッサとマクロによってコンパイラを検出し適切に非標準属性の表示を切り替えることが行われています。しかし、その方法は複雑であり、正しく書くのは難しいものがあります。
この提案は、現在のこの挙動(標準属性タイプミスの検出のための警告)を受け入れつつ、属性構文を拡張することによって、ユーザー/ベンダー定義の属性を全てのコンパイラでサポートされる(無視されるなら警告されない)ようにすることを提案するものです。例えば次のような構文を提案しています
// タイポではない意図的な属性であることを表す [[ extern gnu::access(...) ]];
この提案ではどのような構文やメカニズムを採用するかについては確定しておらず、これ以外の代替案を募集するものでもあります。
P2568R0 Proposal of std::map::at_ptr
.at()
を提供する標準コンテナに、.at_ptr()
メンバ関数を追加する提案。
.at_ptr()
はその名の通り、.at()
して見つかった要素のポインタを返すものです。もし要素が見つからない場合はnullptr
を返し、例外を投げません。
int main() { std::map<int, int> m = /*...*/; if (int* v = m.at_ptr(42)) { // 要素が見つかった場合の処理 } else { // 要素が見つからなかった場合の処理 } }
このように、コンテナ内の特定要素を検索し存在すればそれに対して何かする、という処理はさまざまなプログラムやアルゴリズムで非常によく見られる処理です。しかし、.at()
関数は要素が見つからない場合に例外を投げ、[]
は要素が見つからない場合にデフォルト構築して返すなど使いづらい部分があり、要素の検索と引き当てを別々に書く必要がありました。そのため、そのような典型的なパターンを1まとめにしてこの.at_ptr()
と同じことを行う関数がさまざまなライブラリやプロジェクトに存在しています。この提案は、そのような既存の慣行を標準コンテナのメンバ関数として標準化するものです。
この提案ではすでに.at()
を持っているコンテナのみを対象としています
std::string
std::string_view
std::array
std::vector
std::map
std::unorderd_map
std::deque
また、std::optional
は参照型を保持することが(現在は)できないため、この用途に適しておらず、この提案ではポインタを返すことを提案しています。
P2569R0 *_HAS_SUBNORM==0 implies what?
*_HAS_SUBNORM
を削除する提案。
*_HAS_SUBNORM
とは、<float.h>/<cfloat>
に定義されているマクロで、float, double, long double
型における非正規化数のサポート状況を取得するためのものです。このマクロの値が1
であれば非正規化数がサポートされており、-1
の場合はその判定ができないことを表しています。
0
の場合は非正規化数がサポートされていないことを表していますが、その場合の振る舞いは明確ではありません。例えば、fpclassify()
に非正規化数を渡した場合の動作は不明瞭です。
また、ARM, x86, NVIDIAのGPUなど、非正規化数の扱いに関する制御ビットを持つアーキテクチャが存在しています。その制御ビットの値によって、次のように非正規化数の扱いを変化させることができます
- 非正規化数のオペランドをゼロとして扱う
- 非正規化数の結果をゼロとして扱う(フラッシュ)
ただし、x86は丸めの後に非正規化数を検出し、ARMは丸めの前に検出するなどその振る舞いは実装によって変化しており、さらにはその制御ビットを実行時に変化させる実装が提供されていることもあります。つまりは、*_HAS_SUBNORM
の値はコンパイル時定数ではなく、どちらかといえば実行時に変化する値です。
非正規化数はCの浮動小数点モデルの一部ではありますが必須の要素ではなく、IEC 60559を除いて標準仕様としてその動作を指定するものがありません。非正規化数をサポートする実装は様々に異なる方法で非正規化数を扱います。現在の*_HAS_SUBNORM
は実装や利用の上で曖昧であり、これを解決する方法を見つけることができていません。したがって、この提案では将来の改定のためにも*_HAS_SUBNORM
を削除することを提案しています。
ただし、非正規化数のフラッシュ(非正規化数の結果をゼロにする)は最適化などの点から有用であり広く使用されていることからC標準はそれをサポートし続ける必要があるため、フラッシュされた非正規化数の振る舞いを明確に規定することも同時に提案しています。
これはC標準に対するものですが、SG22を通してC++にも提案されています。