Skip to content

Commit 25ce68b

Browse files
committed
C++26: 「共用体の特殊メンバ関数のトリビアル化」を追加 (close #1417)
1 parent e789283 commit 25ce68b

File tree

7 files changed

+138
-3
lines changed

7 files changed

+138
-3
lines changed

implementation-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@
321321
| P2865R6: [非推奨だった組み込み配列の比較を削除](/lang/cpp26/remove_deprecated_array_comparisons.md) | C++20で非推奨となっていた配列比較を削除 | 15 | 20 | | |
322322
| P1061R10: [構造化束縛でパックを導入できるようにする](/lang/cpp26/structured_bindings_can_introduce_a_pack.md) | タプルを分解する際に複数の変数をパックとして宣言できるようにする。`auto [a, ...xs] = f();` | | | | |
323323
| P3176R0: [先行するカンマのない省略記号を非推奨化](/lang/cpp26/the_oxford_variadic_comma.md) | `void f(int, ...);`はOK。`void f(int...);`は非推奨 | 15 | 20 | | |
324-
| P3074R7: [共用体をトリビアルに未初期化できるようにする](/lang/cpp26/trivial_unions.md.nolink) | `constexpr`での`union U { T storage[N]; };`を許可し、未初期化にできるようにする | | | | |
324+
| P3074R7: [共用体の特殊メンバ関数のトリビアル化](/lang/cpp26/trivial_unions.md) | 非トリビアルな型をメンバにもつ共用体のデフォルトコンストラクタとデストラクタをトリビアルにし、未初期化ストレージとして使用可能にする | | | | |
325325
| P2900R14: [契約プログラミングをサポートする](/lang/cpp26/contracts.md) | 関数の事前条件、事後条件、不変条件を記述できるようにする | | | | |
326326
| P2841R7: [コンセプトと変数テンプレートにテンプレートテンプレートパラメータのサポートを追加](/lang/cpp26/concept_and_variable-template_template-parameters.md.nolink) | テンプレート引数をあとで指定するテンプレートテンプレートパラメータを、コンセプトと変数テンプレートでも使用できるようにする | | | | |
327327
| P1967R14: [ファイルを読み込む`#embed`命令を追加](/lang/cpp26/embed.md) | バイナリファイルをインクルードするメカニズム。`#include`とちがって読み出しサイズなどの柔軟な指定ができる | 15 | | | |

lang/cpp11/constexpr.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ GCC 5.2、Clang 3.7、Visual C++ 2015時点で、3つともデフォルトは512
220220
- [C++26 `constexpr`配置`new`](/lang/cpp26/constexpr_placement_new.md)
221221
- [C++26 `constexpr`構造化束縛の許可と、`constexpr`参照の制限緩和](/lang/cpp26/constexpr_structured_bindings_and_references_to_constexpr_variables.md)
222222
- [C++26 `constexpr`仮想継承を許可](/lang/cpp26/constexpr_virtual_inheritance.md)
223+
- [C++26 共用体の特殊メンバ関数のトリビアル化](/lang/cpp26/trivial_unions.md)
223224
- [C++26 コンパイル時にのみ使用される文字列の扱いを明確化](/lang/cpp26/unevaluated_strings.md)
224225
225226

lang/cpp26.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ C++26とは、2026年中に改訂される予定の、C++バージョンの通
4949

5050
| 言語機能 | 説明 |
5151
|----------|------|
52-
| [共用体をトリビアルに未初期化できるようにする](/lang/cpp26/trivial_unions.md.nolink) | `constexpr`での`union U { T storage[N]; };`を許可し、未初期化にできるようにする |
52+
| [共用体の特殊メンバ関数のトリビアル化](/lang/cpp26/trivial_unions.md) | 非トリビアルな型をメンバにもつ共用体のデフォルトコンストラクタとデストラクタをトリビアルにし、未初期化ストレージとして使用可能にする |
5353

5454

5555
### 属性

lang/cpp26/constexpr_placement_new.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ C++20では、[`std::construct_at()`](/reference/memory/construct_at.md)関数
3737
3838
## <a id="relative-page" href="#relative-page">関連項目</a>
3939
- [C++11 constexpr](/lang/cpp11/constexpr.md)
40+
- [C++26 共用体の特殊メンバ関数のトリビアル化](/lang/cpp26/trivial_unions.md)
4041
- [`new`演算子](/reference/new/op_new.md)
4142
- [`new[]`演算子](/reference/new/op_new[].md)
4243

lang/cpp26/feature_test_macros.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
|`__cpp_structured_bindings`|`202411L`|[構造化束縛への属性を許可](/lang/cpp26/attributes_for_structured_bindings.md)<br/>[構造化束縛でパックを導入できるようにする](/lang/cpp26/structured_bindings_can_introduce_a_pack.md)|
3030
|`__cpp_template_parameters`|`202502L`|コンセプトと変数テンプレートにテンプレートテンプレートパラメータのサポートを追加|
3131
|`__cpp_trivial_relocatability`|`202502L`|トリビアルな再配置|
32-
|`__cpp_trivial_union`|`202502L`|共用体をトリビアルに未初期化できるようにする|
32+
|`__cpp_trivial_union`|`202502L`|[共用体の特殊メンバ関数のトリビアル化](/lang/cpp26/trivial_unions.md)|
3333
|`__cpp_variadic_friend`|`202403L`|[可変引数テンプレートで`friend`宣言をできるようにする](/lang/cpp26/variadic_friends.md)|
3434

3535

lang/cpp26/trivial_unions.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# 共用体の特殊メンバ関数のトリビアル化 [P3074R7]
2+
* cpp26[meta cpp]
3+
4+
<!-- start lang caution -->
5+
6+
このページはC++26に採用される見込みの言語機能の変更を解説しています。
7+
8+
のちのC++規格でさらに変更される場合があるため[関連項目](#relative-page)を参照してください。
9+
10+
<!-- last lang caution -->
11+
12+
## 概要
13+
C++26では、共用体 (`union`) のデフォルトコンストラクタとデストラクタの規則を変更し、より多くの場合にトリビアル (trivial) となるようにする。
14+
15+
これにより、非トリビアルな型のメンバをもつ共用体を未初期化のストレージとして`constexpr`の文脈で使用できるようになる。
16+
17+
```cpp
18+
template <typename T, size_t N>
19+
struct FixedVector {
20+
union { T storage[N]; };
21+
size_t size = 0;
22+
23+
// C++23まで: unionのコンストラクタ/デストラクタが削除されるためコンパイルエラー
24+
// C++26: OK。unionのコンストラクタ/デストラクタはトリビアル
25+
constexpr FixedVector() = default;
26+
27+
constexpr ~FixedVector() {
28+
std::destroy(storage, storage + size);
29+
}
30+
31+
constexpr auto push_back(T const& v) -> void {
32+
std::construct_at(storage + size, v);
33+
++size;
34+
}
35+
};
36+
```
37+
38+
39+
## 仕様
40+
### デフォルトコンストラクタの規則
41+
42+
共用体のデフォルトコンストラクタは、以下の条件を満たす場合にトリビアルとなる:
43+
44+
- デフォルトメンバ初期化子をもつメンバがない
45+
46+
トリビアルなデフォルトコンストラクタは、いかなる初期化も実行しない。ただし、共用体の最初の選択肢 (variant member) が暗黙的寿命型 (implicit-lifetime type) の場合は、そのオブジェクトの寿命が開始され、アクティブメンバとなる。
47+
48+
```cpp
49+
// トリビアルデフォルトコンストラクタ、トリビアルデストラクタ
50+
// sの寿命は開始されない
51+
union U1 { std::string s; };
52+
53+
// 非トリビアルデフォルトコンストラクタ (デフォルトメンバ初期化子がある)
54+
// デストラクタは削除される
55+
union U2 { std::string s = "hello"; };
56+
57+
// トリビアルデフォルトコンストラクタ、トリビアルデストラクタ
58+
// s (配列は暗黙的寿命型) の寿命が開始され、アクティブメンバとなる
59+
union U3 { std::string s[10]; };
60+
```
61+
62+
### デストラクタの規則
63+
64+
共用体のデストラクタは、デフォルトメンバ初期化子をもつメンバが非トリビアルなデストラクタをもつ場合に削除される。それ以外の場合、デストラクタはトリビアルとなる。
65+
66+
```cpp
67+
// トリビアルデストラクタ (デフォルトメンバ初期化子なし)
68+
union U4 { std::string s; };
69+
70+
// 削除されたデストラクタ (デフォルトメンバ初期化子があり、std::stringは非トリビアルデストラクタ)
71+
union U5 { std::string s = "hello"; };
72+
73+
// トリビアルデストラクタ (デフォルトメンバ初期化子はあるが、intはトリビアルデストラクタ)
74+
union U6 { std::string s; int n = 0; };
75+
```
76+
77+
### constexprでの使用
78+
この変更により、共用体を未初期化ストレージとして`constexpr`の文脈で使用できるようになる。
79+
80+
```cpp example
81+
#include <cassert>
82+
#include <new>
83+
84+
constexpr int f() {
85+
union { int s[4]; };
86+
// sは暗黙的寿命型の配列なので、寿命が開始されアクティブメンバとなる
87+
std::construct_at(&s[0], 1);
88+
std::construct_at(&s[1], 2);
89+
std::construct_at(&s[2], 3);
90+
return s[0] + s[1] + s[2];
91+
}
92+
93+
int main() {
94+
static_assert(f() == 6);
95+
}
96+
```
97+
* std::construct_at[link /reference/memory/construct_at.md]
98+
99+
### 既存コードへの影響
100+
- これまで削除されていたコンストラクタ/デストラクタがトリビアルになるケースがあるため、以前はコンパイルエラーだったコードがコンパイル可能になる
101+
- すでに有効なコードの意味は変わらない
102+
- 未初期化オブジェクトへのアクセスは依然として未定義動作
103+
104+
105+
## 備考
106+
### `inplace_vector`への影響
107+
この変更により、[`std::inplace_vector`](/reference/inplace_vector.md)コンテナが非トリビアルな要素型をもつ場合でも`constexpr`で使用できるようになる。
108+
109+
### 非トリビアルデストラクタの実行時コスト
110+
「なにもしないデストラクタ」であっても非トリビアルである場合、コンパイラはデストラクタの呼び出しコードを生成する必要があり、最適化が妨げられる場合がある。デストラクタがトリビアルであればそのようなコードは不要であり、`new[]`式でのcookie (配列要素数の管理情報) も不要になる。
111+
112+
113+
## この機能が必要になった背景・経緯
114+
`constexpr`プログラミングにおいて、未初期化のストレージを扱う需要がある。実行時プログラミングでは`alignas(T) unsigned char buffer[sizeof(T)]`のようなバイト配列を使用できるが、この手法は`constexpr`では動作しない。
115+
116+
代わりに共用体を使用するのが自然なアプローチであるが、非トリビアルな型をメンバにもつ共用体はデフォルトコンストラクタとデストラクタが暗黙的に削除されてしまうため、「なにももしない」コンストラクタとデストラクタを明示的に定義する必要があった。しかし、明示的に定義された「なにももしない」デストラクタはトリビアルではなく、実行時のパフォーマンスコストが発生していた。
117+
118+
この仕様変更により、共用体のコンストラクタとデストラクタの規則を改善し、未初期化ストレージとしての使用を`constexpr`と実行時の両方でゼロコストにする。
119+
120+
121+
## <a id="relative-page" href="#relative-page">関連項目</a>
122+
- [C++11 `constexpr`](/lang/cpp11/constexpr.md)
123+
- [C++26 `constexpr`配置`new`](/lang/cpp26/constexpr_placement_new.md)
124+
- [C++26 定数評価での例外送出を許可](/lang/cpp26/allowing_exception_throwing_in_constant-evaluation.md)
125+
- [`std::inplace_vector`](/reference/inplace_vector/inplace_vector.md)
126+
127+
128+
## 参照
129+
- [P3074R7 trivial unions (was std::uninitialized)](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3074r7.html)

reference/inplace_vector/inplace_vector.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ size: 3
265265
- [Visual C++](/implementation.md#visual_cpp): 2026 Update 2 [mark noimpl]
266266

267267

268+
## 関連項目
269+
- [C++26 共用体の特殊メンバ関数のトリビアル化](/lang/cpp26/trivial_unions.md)
270+
271+
268272
## 参照
269273
- [P0843R14 `inplace_vector`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p0843r14.html)
270274
- [P3074R7 Trivial Unions (was `std::uninitialized<T>`)](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3074r7.html)

0 commit comments

Comments
 (0)