C++標準化委員会の文書: P0430R0-P0439R0
[PDF] P0430R0: File system library on non-POSIX-like operating systems
<filesystem>はPOSIX準拠のファイルシステムを前提にして設計されているが、POSIX以外のファイルシステムの対応も考慮している。その考慮が浅い部分がいくつかあるので修正案。
P0432R0: Implicit and Explicit Default Comparison Operators
暗黙と明示的な比較演算子を生成する提案。
前回の提案では、比較演算子をそれぞれクラスの定義内で=defaultするものであった。これは極めて冗長であり、プリプロセッサーマクロが書かれることが予想できる。
今回の提案は、operator ==とoperator <を=default、=deleteすると、残りは暗黙に生成してくれる。
- 明示的に比較演算子を生成する=defaultの文法
- deleted定義する=deleteの文法
- 生成された比較演算子は条件次第でconstexprやnoexceptになる
- aとbが同じ型の場合、a == bはEquality-by-subobjectする
- aとbが同じ型の場合、a < b はLess-than-by-subobjectする。
- a == b が定義されていてdeleted定義されていない場合、a != b は!(a==b)として生成される
- a < b が定義されていてdeleted定義されておらず a > b がユーザー定義されていない場合、a > b は b < a として暗黙に生成される
- a == bとa < bが定義されていてdeleted定義されておらずa <= bがユーザー定義されていない場合、a <= bはa == bもしくはa < bとして暗黙に生成される
- a <= bが定義されていてdeleted定義されておらず a >= がユーザー定義されていない場合、a >= bはb <= aとして暗黙に生成される。
Equality-by-subobjectは、operator ==を使ってサブオブジェクト同士を比較するものだ。
Less-than-by-subobjectは、operator ==とoperator <を使ってサブオブジェクト同士を比較するものだ。
例えば、
struct A { } ;
に対しては、以下のような比較演算子が生成される。
constexpr bool operator==(A const &, A const &) noexcept {
return true;
}
constexpr bool operator!=(A const &, A const &) noexcept {
return false;
}
以下のコードは、コンパイルエラーになる。
struct B {
A a;
};
bool operator<(B const &, B const &) = default;
理由は、クラスAはoperator <を提供していないからだ。
以下のように書くと、
struct C {
};
bool operator<(C const &, C const &) = default;
以下のような比較演算子が暗黙に生成される。
constexpr bool operator==(C const &, C const &) noexcept {
return true;
}
constexpr bool operator!=(C const &, C const &) noexcept {
return false;
}
constexpr bool operator<(C const &, C const &) noexcept {
return false;
}
constexpr bool operator>(C const &, C const &) noexcept {
return false;
}
constexpr bool operator<=(C const &, C const &) noexcept {
return true;
}
constexpr bool operator>=(C const &, C const &) noexcept {
return true;
}
以下のように書くと、
struct E {
int a;
int b;
std::string c;
bool operator<(E const &) const = default;
bool operator<=(E const &) const = delete;
};
以下のような比較演算子が暗黙に生成される。
inline bool operator==(E const & lhs, E const & rhs) {
return lhs.a == rhs.a and lhs.b == rhs.b and lhs.c == rhs.c;
}
inline bool operator!=(E const & lhs, E const & rhs) {
return !(lhs == rhs);
}
bool E::operator<(E const & other) const {
if (this->a == other.a) {
return false;
}
if (this->a < other.a) {
return true;
}
if (this->b == other.b) {
return false;
}
if (this->b < other.b) {
return true;
}
return this->c < other.c;
}
inline bool operator>(E const & lhs, E const & rhs) {
return rhs < lhs;
}
bool operator<=(E const &, E const &) = delete;
だいぶマシな提案になった。
P0433R0: Toward a resolution of US7 and US14: Integrating template deduction for class templates into the standard library
C++17にはクラステンプレートのコンストラクターに実引数推定が追加された。これにより以下のように書ける。
template < typename T >
struct A { } ;
// A<int>
A a(1) ;
この機能を追加することにより、既存の標準ライブラリにどのような影響を与え、どのような対応が必要か調査が必要だというNBコメントに応える形で、標準ライブラリすべてを調査した結果、多くのライブラリでdeduction guideが必要であることが判明した。
コンストラクターはテンプレート仮引数名以外の型を使うこともあるので、実引数推定ができないことがある。例えばvectorにはイテレーターのペアを取るコンストラクターがある。
template < typename T, typename Allocator = std::allocator >
class vector
{
public :
template < typename Iter >
vector( Iter begin, Iter end ) ;
} ;
このような場合に、deduction guideという文法を使って、型推定のヒントを与えることができる。
template < typename Iter >
vector( Iter, Iter )
-> vector< iterator_traits<Iter>::value_type > ;
この文書は、標準ライブラリでdeduction guideが必要な場所を列挙している。
[PDF] P0434R0: Portable Interrupt Library
ポータブルな割り込み処理のためのライブラリの提案。
割り込み処理はデバイスドライバーやファームウェアの実装に重要な処理であるが、C++は標準の割り込み処理方法を提供していない。そのため、てんでばらばらな方法で実装されている。そこで、標準の割り込み処理用のライブラリを提供することで、割り込み処理をポータブルに書けるようになる。
device_baseはTriggerというpure virtual関数を持っていて、派生して実装する。割り込み番号やタイマー割り込みを処理できと、大雑把なことが書いてある。
趣旨はわかるが、デバイスドライバーやファームウェアのプログラマーは出力されるアセンブリ言語がわかるほどの低級なコードを好むという偏見があるのだが、果たして標準の割り込みライブラリなど可能なのだろうか。
[PDF] P0435R0: Resolving LWG Issues re common_type
common_typeに持ち上がっている様々な問題を解決すべく、コンセプトを用いたcommon_typeの実装の提案。
問題はコンセプトが入らないことだが。
[PDF] P0436R0: An Extensible Approach to Obtaining Selected Operators
比較演算子の自動生成の提案。
比較演算子を自動的に生成するP0221が却下されてしまったので、別の提案が出てきている。この提案では、P0221の問題のない部分だけを入れる提案だ。
常識で考えて、a == bとa != bの結果は異なるものであるべきだ。また、boolを返すoperator <が比較の意味で定義されている場合、その他の演算子も、x > yがy < x、x >= yが!(x < y)、x <= yが!(y < x)と考えるのが最も自然だ。
ならば、この自動的な解釈だけ提案しよう。つまり、a != bと書いて、boolをoperator ==が定義されていて、operator !=が定義されていない時、a != bは!(a == b)と解釈される。その他も比較演算子も同様。
この提案では、比較の大本であるoperator ==とoperator <を自動的に生成することはないが、このふたつの比較を使って他の比較を自動的に生成する。
[PDF] P0437R0: Numeric Traits for the Next Standard Library
<limits>, <cfloat>, <cmath>に点在する数値の特性を取得するメタ関数を、モダンなtraitsベースの設計のライブラリ、<num_traits>に集約する提案。
例えば、numeric_limits<T>::max()と書いていたものを、num_max<T>::valueもしくはnum_max_v<T>もしくはnum_max<T>{}と書ける。
便利なので追加されてほしい。
[PDF] P0438R0: Simplifying simple uses of <random>
P0439R0: Make std::memory_order a scoped enumeration
タイトル通りmemory_orderをscoped enumにする提案。
今のmemory_orderは、C言語風のクソみたいな流儀で定義されている。これは、もともとatomicをCとC++で共通化する目的だったが、C言語はC言語で_Atomicのようなこれまたクソみたいな文法を追加したので、C++としてもmemory_orderをC言語のクソみたいな流儀に合わせる理由は、もはや何もなくなった。
そこで、scoped enumを使う。
現在のクソみたいなmemory_orderの定義
namespace std {
typedef enum memory_order {
memory_order_relaxed, memory_order_consume, memory_order_acquire,
memory_order_release, memory_order_acq_rel, memory_order_seq_cst
} memory_order;
}
これを以下のようにする。
enum class memory_order {
relaxed, consume, acquire, release, acq_rel, seq_cst
};
互換性のために、以下の定義も追加する。
inline constexpr auto memory_order_relaxed = memory_order::relaxed;
inline constexpr auto memory_order_consume = memory_order::consume;
inline constexpr auto memory_order_acquire = memory_order::acquire;
inline constexpr auto memory_order_release = memory_order::release;
inline constexpr auto memory_order_acq_rel = memory_order::acq_rel;
inline constexpr auto memory_order_seq_cst = memory_order::seq_cst;
これは即座に追加されるべきだ。C言語のクソな流儀を取り払え。
ドワンゴ広告
ドワンゴは本物のC++プログラマーを募集しています。
CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0