Skip to content

Commit 7473d6a

Browse files
committed
C++26: 「定数式でのvoid*からポインタ型へのキャストを許可」を追加 (close #1176)
1 parent c8a99ed commit 7473d6a

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

implementation-status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@
296296
| P1854R4: [文字列リテラルの文字エンコーディング失敗を不適格とする](/lang/cpp26/making_non-encodable_string_literals_ill-formed.md) | 文字列リテラルのエンコーディング時に文字表現が失われる場合にコンパイルエラーにする | 14 | 14 | | |
297297
| P2361R6: [コンパイル時にのみ使用される文字列の扱いを明確化](/lang/cpp26/unevaluated_strings.md.nolink) | `static_assert``[[deprecated]]`などで使用されるコンパイル時の文字列について、文字コードの指定を禁止し、実行時エンコーディングが行われないことを規定 | 14 | 18 | | |
298298
| P2552R3: [属性の無視性を見直し](/lang/cpp26/on_the_ignorability_of_standard_attributes.md) | 構文として適格な属性のみを無視できるようにし、そうでない属性の使用を不適格とする | | | | |
299-
| P2738R1: [定数式での`void*`からポインタ型へのキャストを許可](/lang/cpp26/constexpr_cast_from_voidptr.md.nolink) | 型消去のために`void*`からポインタ型へのキャストを許可する | 14 | 17 | | |
299+
| P2738R1: [定数式での`void*`からポインタ型へのキャストを許可](/lang/cpp26/constexpr_cast_from_voidptr.md) | 型消去のために`void*`からポインタ型へのキャストを許可する | 14 | 17 | | |
300300
| P2741R3: [`static_assert`の診断メッセージにユーザーが生成した文字列の指定を許可](/lang/cpp26/user-generated_static_assert_messages.md) | `constexpr``S.size()``S.data()`メンバ関数をもつオブジェクトをコンパイル時文字列として指定できるようにする | 14 | 17 | | |
301301
| P2558R2: [基本文字集合に@、$、\`を追加](/lang/cpp26/add_atsign_dollar_graveaccent_to_the_basic_character_set.md) | C言語との互換性のためにこれらの文字を基本文字集合に追加 | | Yes | | |
302302
| P2662R3: [パラメータパックへのインデックスアクセスを許可](/lang/cpp26/pack_indexing.md.nolink) | 可変引数テンプレートのパラメータパックに添字アクセスできるようにする | 15 | | | |

lang/cpp11/constexpr.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ GCC 5.2、Clang 3.7、Visual C++ 2015時点で、3つともデフォルトは512
216216
- [C++23 `constexpr`関数内での`static constexpr`変数を許可](/lang/cpp23/permitting_static_constexpr_variables_in_constexpr_functions.md)
217217
- [C++23 `constexpr`関数内で`consteval`関数を呼び出せない問題を軽減](/lang/cpp23/consteval_needs_to_propagate_up.md)
218218
- [C++26 定数評価での例外送出を許可](/lang/cpp26/allowing_exception_throwing_in_constant-evaluation.md)
219+
- [C++26 定数式での`void*`からポインタ型へのキャストを許可](/lang/cpp26/constexpr_cast_from_voidptr.md)
219220
220221
221222
## 参照

lang/cpp26.md

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

7676
| 言語機能 | 説明 |
7777
|----------|------|
78-
| [定数式での`void*`からポインタ型へのキャストを許可](/lang/cpp26/constexpr_cast_from_voidptr.md.nolink) | 型消去のために`void*`からポインタ型へのキャストを許可する |
78+
| [定数式での`void*`からポインタ型へのキャストを許可](/lang/cpp26/constexpr_cast_from_voidptr.md) | 型消去のために`void*`からポインタ型へのキャストを許可する |
7979
| [`static_assert`の診断メッセージにユーザーが生成した文字列の指定を許可](/lang/cpp26/user-generated_static_assert_messages.md) | `constexpr``S.size()``S.data()`メンバ関数をもつオブジェクトをコンパイル時文字列として指定できるようにする |
8080
| [`constexpr`配置`new`](/lang/cpp26/constexpr_placement_new.md.nolink) | 定数式の文脈での配置`new`を許可 |
8181
| [`constexpr`構造化束縛の許可と、定数式への参照を定数式とする](/lang/cpp26/constexpr_structured_bindings_and_references_to_constexpr_variables.md.nolink) | 定数式に対する構造化束縛を許可し、関連する定数式への参照が定数式になるようにする |
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# 定数式での`void*`からポインタ型へのキャストを許可 [P2738R1]
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++23までは、定数式の文脈での`void*`から元のポインタ型への変換が禁止されていたが、C++26からは許可される。
14+
15+
`void*`から元のポインタ型への変換は、「型消去 (type erasure)」で有用に使われるもので、標準ライブラリの実装としては[`std::any`](/reference/any/any.md)[`std::function_ref`](/reference/function_ref/functional/funcion_ref.md)[`std::format()`](/reference/format/format.md)などで使われており、これらがコンパイル時に使用できるようにするための必要となる。
16+
17+
型消去は、テンプレートインスタンスの数を減らし、バイナリサイズを小さくするために一般的に使用される技法である。とくに、メモリ制約のある組み込みプラットフォームでは、共通のコードパスを確保するために型消去が有効である。
18+
19+
`void*`から元のポインタ型に変換することによる型消去の例としては、以下のようになる:
20+
21+
```cpp
22+
#include <string_view>
23+
24+
struct Sheep {
25+
constexpr std::string_view speak() const noexcept { return "Baaaaaa"; }
26+
};
27+
struct Cow {
28+
constexpr std::string_view speak() const noexcept { return "Mooo"; }
29+
};
30+
31+
class AnimalView {
32+
private:
33+
const void* animal;
34+
std::string_view (*speak_function)(const void*);
35+
public:
36+
template <typename Animal>
37+
constexpr AnimalView(const Animal &a)
38+
: animal{&a}, speak_function{[](const void* object) {
39+
return static_cast<const Animal*>(object)->speak();
40+
}}
41+
{}
42+
43+
constexpr std::string_view speak() const noexcept {
44+
return speak_function(animal);
45+
}
46+
};
47+
48+
int main() {
49+
constexpr Cow cow;
50+
constexpr AnimalView av{cow};
51+
constexpr auto result = av.speak();
52+
}
53+
```
54+
55+
## 仕様
56+
定数式として許可されない操作を、以下のように変更:
57+
58+
- 変更前:「(CV修飾) `void*` 型からオブジェクトへのポインタ型への変換」
59+
- 変更後:「(CV修飾) `void` へのポインタ型のprvalue (一時オブジェクト) `P` から、オブジェクトへのポインタ型`T`への変換。ただし、`P`が`T`と類似 (similar) の型のオブジェクトを指している場合を除く」
60+
61+
これはつまり、`T`から`void*`を経由して`T`に変換することは許可されるが、`void*`を経由してほかの型に変換することは禁止されたままとなる。
62+
63+
64+
## <a id="relative-page" href="#relative-page">関連項目</a>
65+
- [C++11 constexpr](/lang/cpp11/constexpr.md)
66+
67+
68+
## 参照
69+
- [P2738R1 `constexpr` cast from `void*`: towards `constexpr` type-erasure](http://open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2738r1.pdf)

0 commit comments

Comments
 (0)