static_cast
conversion
暗黙的変換とユーザー定義変換を組み合わせて型間の変換を行います。
目次 |
構文
static_cast<
target-type
>(
expression
)
|
|||||||||
`タグ内のC++固有の用語(`static_cast`)は翻訳せず、元のフォーマットを保持しました。
target-type 型の値を返します。
説明
以下の変換のみが static_cast で実行可能です( const性の除去 (またはvolatile性)を行う場合を除く)。
Base
」型のlvalueであり、かつ
target-type
が「
cv2
Derived
への参照」である場合、以下の条件がすべて満たされるとき、結果は
expression
を包含する
Derived
型のオブジェクトを参照する:
-
Derivedは完全なクラス型である。 -
BaseはDerivedの基底クラスである。 - cv1 は cv2 よりも強いCV修飾ではない。
Derived
型のオブジェクトの基底クラスサブオブジェクトでない場合、動作は未定義です。
struct B {}; struct D : B { B b; }; D d; B& br1 = d; B& br2 = d.b; static_cast<D&>(br1); // OK, lvalue denoting the original “d” object static_cast<D&>(br2); // UB: the “b” subobject is not a base class subobject
|
2)
target-type
が「
Derived
への右辺値参照」であり、かつ
expression
が「(possibly cv-qualified)
Base
」型のxvalueであり、
Base
が
Derived
の基底クラスである場合、その変換の結果と制約は「
Base
左辺値から
Derived
参照への変換」と同じである。
3)
target-type
が右辺値参照型であり、参照される型が
expression
の型と
reference-compatible
である場合、
static_cast
は
glvalue、クラスprvalue、または配列prvalue
(until C++17)
任意の左辺値
(since C++17)
expression
の値を、同じオブジェクトを参照するxvalue、またはその基底クラスの部分オブジェクト(
target-type
に依存)に変換する。
[1]
target-type
が
expression
の型のアクセス不可能または曖昧な基底クラスである場合、プログラムは不適格である。
|
(since C++11) |
|
宣言 target-type temp ( expression ) ; が、ある発明された一時変数 temp に対して適正である場合。 このような明示的変換の効果は、宣言と初期化を実行し、その後 temp を変換の結果として使用するのと同じである。 expression は、初期化がそれを 左辺値 (C++11まで) glvalue (C++11以降) として使用する場合に限り、 左辺値 (C++11まで) glvalue (C++11以降) として使用される。 |
(C++17まで) | ||
|
以下のいずれかの条件が満たされる場合:
明示的変換は以下のように定義される:
|
(C++17以降) |
- lvalue-to-rvalue conversion
- array-to-pointer conversion
- function-to-pointer conversion
- null pointer conversion
- null member pointer conversion
- boolean conversion
| (C++17以降) |
|
a)
スコープ付き列挙型の値は、整数型または浮動小数点型に変換できる。
|
(C++11以降) |
- target-type が固定された基底型を持つ場合、 expression はまず integral promotion または integral conversion によって必要に応じてその型に変換され、その後 target-type に変換されます。
- target-type が固定された基底型を持たない場合、元の値が 列挙値の範囲内 にある場合は expression の値は変更されませんが、そうでない場合の動作は未定義です。
|
d)
浮動小数点型のprvalueは、明示的に他の浮動小数点型に変換できる。
|
(C++23以降) |
Base
」へのポインタは、以下の条件がすべて満たされる場合に型「
cv2
Derived
」へのポインタに明示的に変換できる:
-
Derivedは完全なクラス型である。 -
BaseはDerivedの基底クラスである。 - cv1 は cv2 よりも強いCV修飾ではない。
Base
のオブジェクトを内包する型
Derived
のオブジェクトへのポインタとなる。
-
BaseがDerivedの 仮想基本クラス である場合。 -
BaseがDerivedの仮想基本クラスの基本クラスである場合。 -
「
Derivedへのポインタ」から「Baseへのポインタ」への有効な標準変換が存在しない場合。
Derived
のオブジェクトの基底クラスサブオブジェクトを指していない場合、動作は未定義です。
Derived
のメンバへのポインタで型
cv1
T
」は、以下の条件がすべて満たされる場合、型「
Base
のメンバへのポインタで型
cv2
T
」に明示的に変換できます:
-
Derivedは完全なクラス型である。 -
BaseはDerivedの基底クラスである。 - cv1 は cv2 よりも強いCV修飾ではない。
Base
の元の(間接的な可能性もある)メンバへのポインタです。
Base
型のメンバへのポインタ」から「
Derived
型のメンバへのポインタ」への有効な標準変換が存在しない場合、プログラムは不適格となります。
Base
の(間接的な場合もある)メンバでない場合、動作は未定義です。
T
がオブジェクト型であり、
cv1
が
cv2
よりも強いCV修飾でない場合、「
cv2
T
へのポインタ」型に明示的に変換できる。
|
(C++17まで) |
|
(C++17以降) |
すべてのキャスト式と同様に、結果は次のとおりです:
- target-type が左辺値参照型の場合(または関数型への右辺値参照の場合 (C++11以降) )、左辺値となる;
|
(C++11以降) |
- それ以外の場合は prvalue。
- ↑ この種の static_cast は std::move におけるムーブセマンティクスの実装に使用されます。
- ↑ IEEE演算がサポートされている場合、丸めモードはデフォルトで最近接丸めとなります。
ポインタ相互変換可能なオブジェクト
2つのオブジェクト a と b が ポインタ相互変換可能 である条件は以下の通りです:
- それらが同一のオブジェクトである場合、または
- 一方が共用体オブジェクトで他方がそのオブジェクトの非静的データメンバである場合、または
- 一方が standard-layout クラスオブジェクトで、他方がそのオブジェクトの最初の非静的データメンバ、またはそのオブジェクトの任意の基底クラス部分オブジェクトである場合、または
- オブジェクト c が存在し、 a と c がポインタ相互変換可能であり、かつ c と b がポインタ相互変換可能である場合。
union U { int a; double b; } u; void* x = &u; // xの値は「uへのポインタ」 double* y = static_cast<double*>(x); // yの値は「u.bへのポインタ」 char* z = static_cast<char*>(x); // zの値は「uへのポインタ」
注記
基底クラスから派生クラスへの変換(
ダウンキャスト
)を
static_cast
で行う場合、ポインタ/参照先オブジェクトの
動的型
が
Derived
であることを保証するための実行時チェックは行われません。このため、この前提条件が他の手段(
静的ポリモーフィズム
の実装時など)によって保証されている場合にのみ安全に使用できます。安全なダウンキャストは
dynamic_cast
を使用して行うことができます。
static_cast は、特定の型への関数からポインタへの変換を実行することで、関数のオーバーロードの曖昧さを解消するためにも使用されます。例えば以下のように:
std::for_each(files.begin(), files.end(), static_cast<std::ostream&(*)(std::ostream&)>(std::flush));
キーワード
例
#include <iostream> #include <vector> struct B { int m = 42; const char* hello() const { return "Hello world, this is B!\n"; } }; struct D : B { const char* hello() const { return "Hello world, this is D!\n"; } }; enum class E { ONE = 1, TWO, THREE }; enum EU { ONE = 1, TWO, THREE }; int main() { // 1. 静的ダウンキャスト D d; B& br = d; // 暗黙変換によるアップキャスト std::cout << "1) " << br.hello(); D& another_d = static_cast<D&>(br); // ダウンキャスト std::cout << "1) " << another_d.hello(); // 3. 左辺値から右辺値への変換 std::vector<int> v0{1, 2, 3}; std::vector<int> v2 = static_cast<std::vector<int>&&>(v0); std::cout << "3) ムーブ後、v0.size() = " << v0.size() << '\n'; // 4. 破棄値式 static_cast<void>(v2.size()); // 5. 初期化変換 int n = static_cast<int>(3.14); std::cout << "5) n = " << n << '\n'; std::vector<int> v = static_cast<std::vector<int>>(10); std::cout << "5) v.size() = " << v.size() << '\n'; // 6. 暗黙変換の逆変換 void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "6) *ni = " << *ni << '\n'; // 7a. スコープ付き列挙型からintへの変換 E e = E::TWO; int two = static_cast<int>(e); std::cout << "7a) " << two << '\n'; // 7b. intから列挙型、列挙型から別の列挙型への変換 E e2 = static_cast<E>(two); [[maybe_unused]] EU eu = static_cast<EU>(e2); // 7f. メンバポインタのアップキャスト int D::*pm = &D::m; std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n'; // 7g. void*から任意のオブジェクトポインタへの変換 void* voidp = &e; [[maybe_unused]] std::vector<int>* p = static_cast<std::vector<int>*>(voidp); }
出力:
1) Hello world, this is B! 1) Hello world, this is D! 3) after move, v0.size() = 0 5) n = 3 5) v.size() = 10 6) *ni = 3 7a) 2 7f) 42
不具合報告
以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。
| DR | 適用対象 | 公開時の動作 | 正しい動作 |
|---|---|---|---|
| CWG 137 | C++98 |
void
へのポインタのconst性とvolatile性を
キャストで除去できた |
このような場合、CV修飾を
除去することはできない |
| CWG 427 | C++98 | ダウンキャストが直接初期化と曖昧になる可能性があった | この場合、ダウンキャストを選択する |
| CWG 439 | C++98 |
「オブジェクトへのポインタ」を「
void
へのポインタ」に変換し、
元に戻す場合、結果の型が同じCV修飾を持っている場合のみ その値を保持できた |
CV修飾は
異なっていてもよい |
| CWG 1094 | C++98 | 浮動小数点値から列挙値への変換は未規定であった | 規定された |
| CWG 1320 | C++11 | スコープ付き列挙値からboolへの変換は未規定であった | 規定された |
| CWG 1412 | C++98 |
「
void
へのポインタ」から「オブジェクトへのポインタ」への
変換結果が不明確であった |
明確にされた |
| CWG 1447 | C++11 |
ビットフィールドから右辺値参照への変換は未規定であった
(ビットフィールドへの参照を束縛できない) |
規定された |
| CWG 1766 | C++98 |
整数値または列挙値から列挙値への変換で、
式 が範囲外の場合の結果は未規定であった |
この場合の動作は
未定義である |
| CWG 1832 | C++98 |
整数値または列挙値から列挙値への変換で、
ターゲット型 が不完全型であることを許可していた |
許可されない |
| CWG 2224 | C++98 |
基底クラス型のメンバから派生クラス型の完全オブジェクトへの
変換は有効であった |
この場合の動作は
未定義である |
| CWG 2254 | C++11 |
データメンバを持たないstandard-layoutクラスオブジェクトは
その最初の基底クラスとポインタ相互変換可能であった |
その任意の基底クラスと
ポインタ相互変換可能である |
| CWG 2284 | C++11 |
non-standard-layout共用体オブジェクトとその非静的データ
メンバはポインタ相互変換可能ではなかった |
ポインタ相互変換可能である |
| CWG 2310 | C++98 |
基底から派生へのポインタ変換と
派生から基底へのポインタ対メンバ変換において、 派生クラス型は不完全型でもよかった |
完全型でなければならない |
| CWG 2338 | C++11 |
固定された基底型を持つ列挙型への変換で、
式 が範囲外の場合、未定義動作となった |
まず基底型に変換する
(未定義動作なし) |
| CWG 2499 | C++11 |
standard-layoutクラスは、すべての基底サブオブジェクトが
同じアドレスを持つにもかかわらず、ポインタ相互変換不可能な 基底クラスを持つ可能性があった |
持たない |
| CWG 2718 | C++98 |
基底から派生への参照変換において、
派生クラス型は不完全型でもよかった |
完全型でなければならない |
| CWG 2882 | C++98 |
static_cast
<
void
>
(
expr
)
が
expr から void への暗黙の変換シーケンスを 形成しようとするかどうかが不明確であった |
この場合、試行しない |
参考文献
- C++23規格 (ISO/IEC 14882:2024):
-
- 7.6.1.9 静的キャスト [expr.static.cast]
- C++20規格 (ISO/IEC 14882:2020):
-
- 7.6.1.8 Static cast [expr.static.cast]
- C++17標準 (ISO/IEC 14882:2017):
-
- 8.2.9 Static cast [expr.static.cast]
- C++14 標準 (ISO/IEC 14882:2014):
-
- 5.2.9 Static cast [expr.static.cast]
- C++11標準 (ISO/IEC 14882:2011):
-
- 5.2.9 Static cast [expr.static.cast]
- C++98標準 (ISO/IEC 14882:1998):
-
- 5.2.9 静的キャスト [expr.static.cast]
- C++03標準 (ISO/IEC 14882:2003):
-
- 5.2.9 Static cast [expr.static.cast]