static_cast 変換
From cppreference.com
暗黙の型変換とユーザー定義変換を組み合わせて型を変換します。
目次 |
[編集] 構文
static_cast<ターゲット型 >(式 ) |
|||||||||
ターゲット型の値を返します。
[編集] 説明
static_cast で実行できる変換は、そのような変換が const 性 (または volatile 性) を 剥奪する 場合を除き、以下のものだけです。
1) 式 が型 "cv1
Base" の左辺値であり、ターゲット型 が "cv2 Derived" への参照である場合、以下のすべての条件が満たされれば、結果は 式 を包含する 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) ターゲット型 が "
Derived への右辺値参照" であり、式 が "(cv 修飾される場合がある) Base" 型の xvalue で、かつ Base が Derived の基底クラスである場合、そのような変換の結果および制約は、"Base 左辺値から Derived 参照" 変換のものと同じです。3) ターゲット型 が右辺値参照型であり、参照される型が 式 の型と 参照互換 である場合、static_cast は glvalue、クラスの prvalue、または配列の prvalue(C++17 まで)任意の左辺値(C++17 以降) 式 の値を、その式と同じオブジェクトを参照する xvalue、またはその基底クラスサブオブジェクト (ターゲット型による) に変換します。[1]
ターゲット型 がアクセス不能または曖昧な 式 の型の基底クラスである場合、プログラムは不正形式です。
式 が ビットフィールド の左辺値である場合、まず基底となる型への prvalue に変換されます。
|
(C++11以降) |
5) それ以外の場合、式 は、以下の条件が満たされる場合に ターゲット型 に明示的に変換できます。
|
ある一時的な変数 temp を導入した場合、宣言 ターゲット型 temp(式 ); が well-formed である。 そのような明示的な変換の効果は、宣言と初期化を実行し、その後変換の結果として temp を使用するのと同じです。式 は、初期化がそれを 左辺値(C++11 まで)glvalue(C++11 以降) として使用する場合に限り、左辺値(C++11 まで)glvalue(C++11 以降) として使用されます。 |
(C++17まで) | ||
|
以下のいずれかの条件が満たされる。
明示的な変換は次のように定義されます。
|
(C++17以降) |
6) それ以外の場合、式 から ターゲット型 への変換が標準変換シーケンスの逆であり、かつ変換シーケンスに以下のいずれかの変換が含まれていない場合、static_cast によって変換を実行できます。
| (C++17以降) |
プログラムが不正形式の標準変換シーケンスの逆を実行するために static_cast を使用する場合、それは不正形式です。
7) それ以外の場合、式 に左辺値から右辺値、配列からポインタ、および関数からポインタへの変換が適用されます。これらの変換の後、static_cast で実行できる変換は以下のものだけです。
|
a) スコープ付き列挙型 の値は、整数型または浮動小数点型に変換できます。
|
(C++11以降) |
b) 整数型または列挙型の値は、任意の完全な列挙型に変換できます。
|
d) 浮動小数点型の prvalue は、他の任意の浮動小数点型に明示的に変換できます。
|
(C++23から) |
e) "cv1
Base へのポインタ" 型の 右辺値(C++11 まで)prvalue(C++11 以降) は、以下のすべての条件が満たされる場合、"cv2 Derived へのポインタ" 型に明示的に変換できます。-
Derivedは完全なクラス型である。 -
BaseはDerivedの基底クラスである。 - cv1 は cv2 よりも限定された cv 修飾ではない。
式 が ヌルポインタ値 である場合、結果は ターゲット型 のヌルポインタ値になります。それ以外の場合、結果は 式 が指す
Base 型のオブジェクトを包含する Derived 型のオブジェクトへのポインタになります。 以下のいずれかの条件が満たされる場合、プログラムは不正形式です。
-
BaseはDerivedの 仮想基底クラス である。 -
BaseはDerivedの仮想基底クラスの基底クラスである。 - "ポインタから
Derived" から "ポインタからBase" への有効な標準変換が存在しない。
式 がヌルポインタ値ではなく、実際には
Derived 型のオブジェクトの基底クラスサブオブジェクトを指していない場合、動作は未定義です。f) "
Derived のメンバー、型 cv1 T へのポインタ" 型の 右辺値(C++11 まで)prvalue(C++11 以降) は、以下のすべての条件が満たされる場合、"Base のメンバー、型 cv2 T へのポインタ" 型に明示的に変換できます。-
Derivedは完全なクラス型である。 -
BaseはDerivedの基底クラスである。 - cv1 は cv2 よりも限定された cv 修飾ではない。
式 がヌルメンバポインタ値である場合、結果は ターゲット型 のヌルメンバポインタ値になります。それ以外の場合、結果はクラス
Base の元の (場合によっては間接的な) メンバーへのポインタになります。 "
Base のメンバー、型 T へのポインタ" から "Derived のメンバー、型 T へのポインタ" への有効な標準変換が存在しない場合、プログラムは不正形式です。 式 がヌルメンバポインタ値ではなく、それが示すメンバーがクラス
Base の (場合によっては間接的な) メンバーでない場合、動作は未定義です。g) "cv1 void へのポインタ" 型の 右辺値(C++11 まで)prvalue(C++11 以降) は、
T がオブジェクト型であり、かつ cv1 が cv2 よりも限定された cv 修飾ではない場合、"cv2 T へのポインタ" 型に明示的に変換できます。| (C++17まで) | |
|
(C++17以降) |
すべてのキャスト式と同様に、結果は次のようになります。
- ターゲット型がlvalue参照型である場合、または関数型へのrvalue参照である場合、lvalueになります (C++11以降)。
|
(C++11以降) |
- それ以外の場合はprvalueになります。
- ↑ この種類の static_cast は、std::move でムーブセマンティクスを実装するために使用されます。
- ↑ IEEE 算術演算がサポートされている場合、丸めはデフォルトで最近接になります。
[編集] ポインタ相互変換可能なオブジェクト
2 つのオブジェクト a と b は、以下の場合に ポインタ相互変換可能 となります。
- それらが同じオブジェクトである場合、または
- 一方が共用体オブジェクトであり、他方がそのオブジェクトの非静的データメンバーである場合、または
- 一方が 標準レイアウト クラスオブジェクトであり、他方がそのオブジェクトまたはそのオブジェクトの任意の基底クラスサブオブジェクトの最初の非静的データメンバーである場合、または
- オブジェクト c が存在し、a と c がポインタ相互変換可能であり、かつ c と b がポインタ相互変換可能である場合。
union U { int a; double b; } u; void* x = &u; // x's value is “pointer to u” double* y = static_cast<double*>(x); // y's value is “pointer to u.b” char* z = static_cast<char*>(x); // z's value is “pointer to 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. static downcast D d; B& br = d; // upcast via implicit conversion std::cout << "1) " << br.hello(); D& another_d = static_cast<D&>(br); // downcast std::cout << "1) " << another_d.hello(); // 3. lvalue to xvalue std::vector<int> v0{1, 2, 3}; std::vector<int> v2 = static_cast<std::vector<int>&&>(v0); std::cout << "3) after move, v0.size() = " << v0.size() << '\n'; // 4. discarded-value expression static_cast<void>(v2.size()); // 5. initializing conversion 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. inverse of implicit conversion void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "6) *ni = " << *ni << '\n'; // 7a. scoped enum to int E e = E::TWO; int two = static_cast<int>(e); std::cout << "7a) " << two << '\n'; // 7b. int to enum, enum to another enum E e2 = static_cast<E>(two); [[maybe_unused]] EU eu = static_cast<EU>(e2); // 7f. pointer to member upcast int D::*pm = &D::m; std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n'; // 7g. void* to any object pointer 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 | データメンバーを持たない標準レイアウトクラス は、その最初の基底クラスとポインタ相互変換可能だった |
それは 任意の基底クラスとポインタ相互変換可能である |
| CWG 2284 | C++11 | 非標準レイアウトの共用体オブジェクトと、そのオブジェクトの非静的データ メンバーはポインタ相互変換可能ではなかった |
現在は |
| CWG 2310 | C++98 | 基底クラスから派生クラスへのポインタ変換と 派生クラスから基底クラスへのメンバポインタ変換では、 派生クラス型は不完全でもよかった |
完全でなければならない |
| CWG 2338 | C++11 | 固定された基底型を持つ列挙型への 変換は、式 が範囲外の場合に未定義の動作をもたらした |
まず基底となる型に 変換する (未定義の動作なし) |
| CWG 2499 | C++11 | 標準レイアウトクラスが、ポインタ相互変換可能ではない 基底クラスを持つ可能性があったが、すべての基底サブオブジェクトは同じアドレスを持っていた |
持っていなかった |
| CWG 2718 | C++98 | 基底クラスから派生クラスへの参照変換では、 派生クラス型は不完全でもよかった |
完全でなければならない |
| CWG 2882 | C++98 | static_cast<void>(expr) が試みるかどうか 暗黙の変換シーケンスを expr から void へ形成しようとするか |
この場合、試みはない |
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 7.6.1.9 Static cast [expr.static.cast]
- C++20 standard (ISO/IEC 14882:2020)
- 7.6.1.8 Static cast [expr.static.cast]
- C++17 standard (ISO/IEC 14882:2017)
- 8.2.9 Static cast [expr.static.cast]
- C++14 standard (ISO/IEC 14882:2014)
- 5.2.9 Static cast [expr.static.cast]
- C++11 standard (ISO/IEC 14882:2011)
- 5.2.9 Static cast [expr.static.cast]
- C++98 標準 (ISO/IEC 14882:1998)
- 5.2.9 Static cast [expr.static.cast]
- C++03 標準 (ISO/IEC 14882:2003)
- 5.2.9 Static cast [expr.static.cast]