Explicit type conversion
明示的変換と暗黙的変換を組み合わせて型間の変換を行います。
目次 |
構文
(
型ID
)
単項式
|
(1) | ||||||||
単純型指定子
(
式リスト
(オプション)
)
単純型指定子
(
初期化子リスト
(オプション)
)
|
(2) |
(C++11以前)
(C++11以降) |
|||||||
単純型指定子
{
初期化子リスト
(オプション)
}
|
(3) | (C++11以降) | |||||||
単純型指定子
{
指定初期化子リスト
}
|
(4) | (C++20以降) | |||||||
typename
識別子
(
初期化子リスト
(オプション)
)
|
(5) | (C++11以降) | |||||||
typename
識別子
{
初期化子リスト
(オプション)
}
|
(6) | (C++11以降) | |||||||
typename
識別子
{
指定初期化子リスト
}
|
(7) | (C++20以降) | |||||||
任意の数の値をターゲット型の値に明示的に変換します。
| type-id | - | 型ID( type-id ) |
| unary-expression | - | 単項式(最上位演算子の優先順位がCスタイルキャスト以下のもの) |
| simple-type-specifier | - | 単純型指定子( simple type specifier ) |
| expression-list | - | カンマ区切りの式リスト(括弧で囲まれていない comma expressions を除く) |
| initializer-list | - | カンマ区切りの initializer clauses リスト |
| designated-initializer-list | - | カンマ区切りの designated initializer clauses リスト |
| identifier | - | (修飾された可能性のある)識別子( template identifiers を含む) |
説明
const_cast
<
type-id
>
(
unary-expression
)
;
static_cast
<
type-id
>
(
unary-expression
)
、拡張機能として:
派生クラス
へのポインタまたは参照は、基底クラスが
アクセス不可能
であっても(つまり、このキャストはprivate継承指定子を無視する)、明確な基底クラスへのポインタまたは参照に追加でキャスト可能(逆も同様)。同じことが、明確な非仮想基底クラスのメンバへのポインタへの
メンバへのポインタ
のキャストにも適用される;
reinterpret_cast
<
type-id
>
(
unary-expression
)
;
T
の値を構築します。
T
は指定された型
と初期化子から決定されます
(C++17以降)
:
|
|
(C++17以前) | ||
|
|
(C++17以降) |
- 関数形式キャストが構文 (2) であり、括弧内に式が1つだけ存在する場合、このキャストは対応するC形式キャストと等価です。
-
それ以外の場合、
Tが(cv修飾可能性のある) void の場合、結果は初期化を実行しない void 型の 右辺値 (C++11まで) 純粋右辺値 (C++11以降) です。
|
(C++11まで) |
|
(C++11以降) |
-
それ以外の場合、
Tが参照型の場合、関数形式キャストは型Tの仮想変数 t を指定された初期化子から 直接初期化 するのと同じ効果を持ち、結果は初期化された t です。
|
(C++11まで) |
|
(C++11以降) |
-
それ以外の場合、結果は指定された初期化子で
直接初期化
された
一時オブジェクトを指す
(C++17まで)
結果オブジェクトが
(C++17以降)
T型の 右辺値 (C++11まで) 純粋右辺値 (C++11以降) です。
曖昧性解決
曖昧な宣言文
関数形式キャスト式を左端の部分式とする式文と宣言文の間で曖昧性が生じる場合、その曖昧性は宣言として扱うことで解決されます。この曖昧性の解消は純粋に構文的なものです:文内に現れる名前が型名であるかどうか以外の意味は考慮されません:
struct M {}; struct L { L(M&); }; M n; void f() { M(m); // 宣言、M m; と同等 L(n); // 不正な宣言、L n; と同等 L(l)(m); // 依然として宣言、L l((m)); と同等 }
|
ただし、曖昧な宣言文の最も外側の宣言子が 後置戻り値型 を持つ場合、その宣言文は後置戻り値型が auto で始まる場合にのみ宣言文として扱われます: struct M; struct S { S* operator()(); int N; int M; void mem(S s) { auto(s)()->M; // 式 (S::M が ::M を隠蔽)、C++23 以前では無効 } }; void f(S s) { { auto(s)()->N; // 式、C++23 以前では無効 auto(s)()->M; // 関数宣言、M s(); と等価 } { S(s)()->N; // 式 S(s)()->M; // 式 } } |
(C++11 以降) |
曖昧な関数パラメータ
上記の曖昧性は、宣言の文脈でも発生することがあります。その文脈では、関数形式のキャストを初期化子とするオブジェクト宣言と、パラメータ名を冗長な括弧で囲んだ関数宣言子を含む宣言との間の選択が問題となります。解決策も同様に、潜在的なパラメータ宣言など、宣言である可能性のある構文はすべて宣言として扱うことです:
struct S { S(int); }; void foo(double a) { S w(int(a)); // 関数宣言: int型のパラメータ`a`を持つ S x(int()); // 関数宣言: int(*)()型の無名パラメータを持つ // int()から調整されたもの // 曖昧性を回避する方法: S y((int(a))); // オブジェクト宣言: 追加の括弧ペア S y((int)a); // オブジェクト宣言: Cスタイルキャスト S z = int(a); // オブジェクト宣言: この構文では曖昧性なし }
|
ただし、あいまいなパラメータ宣言の最も外側の宣言子が 後置戻り値型 を持つ場合、そのあいまいさは auto で始まる場合にのみ、宣言として扱うことで解決されます: typedef struct BB { int C[2]; } *B, C; void foo() { S a(B()->C); // オブジェクト宣言: B()->C はパラメータを宣言できない S b(auto()->C); // 関数宣言: C(*)() 型の名前なしパラメータを持つ // C() から調整されたもの } |
(C++11以降) |
曖昧な型ID
関数形式のキャストと type-id の類似性から曖昧性が生じることがあります。解決策は、構文的な文脈においてtype-idである可能性がある構文はすべてtype-idとして扱われるというものです:
// `int()` と `int(unsigned(a))` は両方とも型IDとして解析可能: // `int()` は int を返し、引数を取らない関数を表す // `int(unsigned(a))` は int を返し、unsigned 型の引数を取る関数を表す void foo(signed char a) { sizeof(int()); // 型ID (不正形式) sizeof(int(a)); // 式 sizeof(int(unsigned(a))); // 型ID (不正形式) (int()) + 1; // 型ID (不正形式) (int(a)) + 1; // 式 (int(unsigned(a))) + 1; // 型ID (不正形式) }
|
ただし、あいまいな type-id において、最も外側の abstract-declarator が trailing return type を持つ場合、その曖昧性は auto で始まる場合にのみtype-idとして解決される: typedef struct BB { int C[2]; } *B, C; void foo() { sizeof(B()->C[1]); // OK, sizeof(expression) sizeof(auto()->C[1]); // error: sizeof of a function returning an array } |
(C++11以降) |
注記
| 機能テストマクロ | 値 | 規格 | 機能 |
|---|---|---|---|
__cpp_auto_cast
|
202110L
|
(C++23) | auto ( x ) および auto { x } |
例
#include <cassert> #include <iostream> double f = 3.14; unsigned int n1 = (unsigned int)f; // Cスタイルキャスト unsigned int n2 = unsigned(f); // 関数スタイルキャスト class C1; class C2; C2* foo(C1* p) { return (C2*)p; // 不完全型から不完全型へのキャスト } void cpp23_decay_copy_demo() { auto inc_print = [](int& x, const int& y) { ++x; std::cout << "x:" << x << ", y:" << y << '\n'; }; int p{1}; inc_print(p, p); // x:2 y:2 を出力(ここでのパラメータyはpのエイリアス) int q{1}; inc_print(q, auto{q}); // x:2 y:1 を出力、auto{q} (C++23) はprvalueにキャストされ、 // パラメータyはqのコピーとなる(qのエイリアスではない) } // この例では、Cスタイルキャストはreinterpret_castとして動作する可能性があるにもかかわらず、 // static_castとして解釈される struct A {}; struct I1 : A {}; struct I2 : A {}; struct D : I1, I2 {}; int main() { D* d = nullptr; // A* a = (A*)d; // コンパイルエラー A* a = reinterpret_cast<A*>(d); // これはコンパイル可能 assert(a == nullptr); cpp23_decay_copy_demo(); }
出力:
x:2 y:2 x:2 y:1
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
|
CWG 1223
( P2915R0 ) |
C++11 | 後置戻り値型の追加により、より多くの曖昧性が導入された | それらを解決する |
| CWG 1893 | C++11 | 関数形式キャストはパック展開を考慮していなかった | それらを考慮する |
| CWG 2351 | C++11 | void { } は不適格であった | 適格とした |
| CWG 2620 | C++98 | 曖昧な関数パラメータの解決が誤って解釈される可能性があった | 文言を改善した |
| CWG 2828 | C++98 |
複数の
static_cast
に
const_cast
が続く解釈が存在する場合、
実際にこれらの変換が使用されるかどうかに関わらず、 C形式キャストは不適格であった |
実際に使用される可能性のある
変換のみを 考慮する |
| CWG 2894 | C++98 | 関数形式キャストは参照右辺値を生成できた | 参照左辺値のみを生成できる |
参考文献
- C++23規格 (ISO/IEC 14882:2024):
-
- 7.6.1.4 明示的型変換(関数表記)[expr.type.conv]
-
- 7.6.3 明示的型変換(キャスト表記)[expr.cast]
- C++20 標準 (ISO/IEC 14882:2020):
-
- 7.6.1.4 明示的型変換(関数表記)[expr.type.conv]
-
- 7.6.3 明示的型変換(キャスト表記)[expr.cast]
- C++17標準 (ISO/IEC 14882:2017):
-
- 8.2.3 明示的型変換(関数表記)[expr.type.conv]
-
- 8.4 明示的型変換(キャスト表記)[expr.cast]
- C++14標準 (ISO/IEC 14882:2014):
-
- 5.2.3 明示的型変換(関数表記)[expr.type.conv]
-
- 5.4 明示的型変換(キャスト表記)[expr.cast]
- C++11標準 (ISO/IEC 14882:2011):
-
- 5.2.3 明示的型変換 (関数表記) [expr.type.conv]
-
- 5.4 明示的型変換 (キャスト表記) [expr.cast]
- C++03標準 (ISO/IEC 14882:2003):
-
- 5.2.3 明示的型変換 (関数形式記法) [expr.type.conv]
-
- 5.4 明示的型変換 (キャスト記法) [expr.cast]
- C++98標準 (ISO/IEC 14882:1998):
-
- 5.2.3 明示的型変換(関数表記)[expr.type.conv]
-
- 5.4 明示的型変換(キャスト表記)[expr.cast]
関連項目
const_cast
変換
|
constの追加または削除 |
static_cast
変換
|
基本的な変換を実行 |
dynamic_cast
変換
|
チェック付きポリモーフィック変換を実行 |
reinterpret_cast
変換
|
一般的な低レベル変換を実行 |
| 標準変換 | ある型から別の型への暗黙的変換 |
|
Cドキュメント
for
キャスト演算子
|
|