Skip to content

Commit

Permalink
P0848R3: 仕様と背景追加 #1106
Browse files Browse the repository at this point in the history
  • Loading branch information
onihusube committed Jan 29, 2025
1 parent 1e87d12 commit 3025ea8
Showing 1 changed file with 38 additions and 7 deletions.
45 changes: 38 additions & 7 deletions lang/cpp20/conditionally_trivial_special_member_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
```cpp
template<typename T>
struct wrap {
T t;

// 1. 制約されたdefaultなコピーコンストラクタ
wrap(const wrap&) requires std::is_trivially_copy_constructible_v<T> = default;
Expand All @@ -23,14 +24,43 @@ struct wrap {
};
```
`T`が`std::is_trivially_copy_constructible`を満たす場合、1の宣言が選択され`wrap<T>`のコピーコンストラクタは`default`実装される(2のコンストラクタが選択されることは無い)。`T`が`std::is_trivially_copy_constructible`を満たさない場合、2の宣言が選択され`wrap<T>`のコピーコンストラクタはユーザー定義される。
`T`が`std::is_trivially_copy_constructible`を満たす場合、1の宣言が選択され`wrap<T>`のコピーコンストラクタは`default`実装される(2のコンストラクタが選択されることは無い)。`T`が`std::is_trivially_copy_constructible`を満たさない場合、2の宣言が選択され`wrap<T>`のコピーコンストラクタはユーザー定義される(1のコンストラクタが選択されることは無い)
特に、`T`がトリビアルコピー可能である場合にこの仕組みによって1のコンストラクタが選択されれば、(他の条件を満たしているものとして)`wrap<T>`もまたトリビアルコピー可能となる。
特に、`T`がトリビアルコピー可能である場合にこの仕組みによって1のコンストラクタが選択されれば、(他の条件を満たしているものとして)`wrap<T>`もまたトリビアルコピー可能となる。トリビアル性に関する他の性質も同様に伝播することが可能となる。
## 仕様
(執筆中)
次のいずれかの場合、2つの特殊メンバ関数は同種となる
1. 両方ともデフォルトコンストラクタ
2. 両方ともコピー/ムーブコンストラクタであり、最初の引数型が同じ
3. 両方ともコピー/ムーブ代入演算子であり、最初の引数型と参照・CV修飾が同じ
ある特殊メンバ関数が次の全てを満たす場合、それは資格のある(*eligible*)特殊メンバ関数となる
1. `delete`されていない
2. 関連制約がある場合(コンセプト機能により制約がなされている場合)、それが満たされている
3. 同種の特殊メンバ関数で、より制約されているものがない
次に、宣言されている全てのデストラクタはデストラクタ候補(*prospective destructor*)として扱われるようになる。そして、クラスの定義の最後(`};`が出現した場所と思って差し支えない)において、全てのデストラクタ候補の間で空の引数リストで呼び出す形でオーバーロード解決を実行し、そのクラスのデストラクタを選択する。
こうして選ばれたデストラクタの事を選択されたデストラクタ(*selected destructor*)とも呼ぶが、この選択されたデストラクタだけがそのクラスのデストラクタとなる(規格書中の他のすべての箇所で単にデストラクタ(*destructor*)と呼ばれるものは、この選択されたデストラクタの事を指す)。なお、何らかの理由でオーバーロード解決が失敗した場合、プログラムは不適格となる。
そして、あるクラスは次の条件を全て満たす場合にトリビアルコピー可能である
1. 少なくとも1つの、資格のあるコピーコンストラクタ、ムーブコンストラクタ、コピー代入演算子、またはムーブ代入演算子を持つ
2. それら資格のあるコピーコンストラクタ、ムーブコンストラクタ、コピー代入演算子、ムーブ代入演算子、はそれぞれすべてトリビアルである
3. トリビアルで削除されていないデストラクタ(選択されたデストラクタ)を持つ
また、あるクラスは次の条件をすべて満たす場合にトリビアルである
1. トリビアルコピー可能である
2. 1つ以上の資格のあるデフォルトコンストラクタを持つ
3. それらのデフォルトコンストラクタは全てトリビアルである
`default`宣言の扱いについては、選択されたデストラクタ以外の`default`指定されたデストラクタ候補は`delete`定義され、デストラクタ候補でも資格があるわけでもない`default`指定された特殊メンバ関数は`delete`定義される。
コンセプトによって制約された特殊メンバ関数があるとき、どれが使用されるか(オーバーロード解決)については通常の制約された関数と同じルールに従って選択される。そして、そのような特殊メンバ関数を持つ型のトリビアル性に関する性質については、特殊メンバ関数のオーバーロードのうち資格があるもの(デストラクタの場合は選択されたもの)によって決定される。
## 例
Expand All @@ -57,13 +87,13 @@ int main()

## この機能が必要になった背景・経緯

(執筆中)

例にあるように、C++17まで、`std::optional`のようにテンプレートパラメータで指定された型の値を保持するラッパクラス型において、その指定された型のトリビアル性を伝播するためには非常に複雑な実装を必要としていた。

## 検討されたほかの選択肢
C++20のコンセプトの導入によって、コンセプトによって特殊メンバ関数の宣言を選択することができるようになっていたものの、トリビアル性(特にトリビアルコピー可能性)の規格上の定義がそれを考慮したものになっておらず、コンセプトによる特殊メンバ関数の選択は仕様として完全なものではなかった。

(執筆中)
この機能はそれを補うための仕組みであり、特殊メンバ関数に対するコンセプト制約自体は最初のコンセプト導入時から可能になっていたため、この機能は厳密にいえば仕様の調整のみである。

この機能は、C++23の`std::expceted`の実装で活用されるだろう。

## ## <a id="relative-page" href="#relative-page">関連項目</a>

Expand All @@ -73,3 +103,4 @@ int main()

- [P0848R0 Conditionally Trivial Special Member Functions](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0848r0.html)
- [P0848R3 Conditionally Trivial Special Member Functions](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0848r3.html)
- [What is a "prospective destructor" in C++20? - stackoverflow](https://stackoverflow.com/questions/66055641/what-is-a-prospective-destructor-in-c20)

0 comments on commit 3025ea8

Please sign in to comment.