名前空間
変種
操作

static_cast 変換

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

暗黙の型変換とユーザー定義変換を組み合わせて型を変換します。

目次

[編集] 構文

static_cast<ターゲット型 >( )

ターゲット型の値を返します。

[編集] 説明

static_cast で実行できる変換は、そのような変換が const 性 (または volatile 性) を 剥奪する 場合を除き、以下のものだけです。

1) が型 "cv1 Base" の左辺値であり、ターゲット型 が "cv2 Derived" への参照である場合、以下のすべての条件が満たされれば、結果は を包含する Derived 型のオブジェクトを参照します。
  • Derived は完全なクラス型である。
  • BaseDerived の基底クラスである。
  • cv1cv2 よりも限定された cv 修飾ではない。
以下のいずれかの条件が満たされる場合、プログラムは不正形式です。
  • BaseDerived仮想基底クラス である。
  • BaseDerived の仮想基底クラスの基底クラスである。
  • "ポインタから Derived" から "ポインタから Base" への有効な 標準変換 が存在しない。
が実際には 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 で、かつ BaseDerived の基底クラスである場合、そのような変換の結果および制約は、"Base 左辺値から Derived 参照" 変換のものと同じです。
3) ターゲット型 が右辺値参照型であり、参照される型が の型と 参照互換 である場合、static_castglvalue、クラスの prvalue、または配列の prvalue(C++17 まで)任意の左辺値(C++17 以降) の値を、その式と同じオブジェクトを参照する xvalue、またはその基底クラスサブオブジェクト (ターゲット型による) に変換します。[1]
ターゲット型 がアクセス不能または曖昧な の型の基底クラスである場合、プログラムは不正形式です。
ビットフィールド の左辺値である場合、まず基底となる型への prvalue に変換されます。
(C++11以降)
4) ターゲット型 が (cv 修飾される場合がある) void である場合、変換には結果がありません。この場合、破棄値式 です。
5) それ以外の場合、 は、以下の条件が満たされる場合に ターゲット型 に明示的に変換できます。

ある一時的な変数 temp を導入した場合、宣言 ターゲット型 temp( ); が well-formed である。

そのような明示的な変換の効果は、宣言と初期化を実行し、その後変換の結果として temp を使用するのと同じです。  は、初期化がそれを 左辺値(C++11 まで)glvalue(C++11 以降) として使用する場合に限り、左辺値(C++11 まで)glvalue(C++11 以降) として使用されます。

(C++17まで)

以下のいずれかの条件が満たされる。

  • から ターゲット型 への暗黙の変換シーケンスが存在する。
  • ターゲット型 のオブジェクトまたは参照の 直接初期化 における からの オーバーロード解決 が、少なくとも 1 つの有効な関数を見つける。
  • ターゲット型 は、最初の要素 x を持ち、かつ から x の型への暗黙の変換シーケンスが存在するような 集計型 である。
(C++20以降)

明示的な変換は次のように定義されます。

  • ターゲット型 が参照型の場合、効果は、ある一時的な変数 temp を導入して宣言と初期化 ターゲット型 temp( ); を実行し、その後、変換の結果として temp を使用するのと同じです。
  • それ以外の場合、結果オブジェクトは   から直接初期化されます。
(C++17以降)
6) それ以外の場合、 から ターゲット型 への変換が標準変換シーケンスの逆であり、かつ変換シーケンスに以下のいずれかの変換が含まれていない場合、static_cast によって変換を実行できます。
(C++17以降)
プログラムが不正形式の標準変換シーケンスの逆を実行するために static_cast を使用する場合、それは不正形式です。
7) それ以外の場合、 に左辺値から右辺値、配列からポインタ、および関数からポインタへの変換が適用されます。これらの変換の後、static_cast で実行できる変換は以下のものだけです。
a) スコープ付き列挙型 の値は、整数型または浮動小数点型に変換できます。
  • (cv 修飾される場合がある) boolターゲット型 である場合、元の の値がゼロであれば結果は false、それ以外の値であれば true になります。
  • (cv 修飾される場合がある) bool 以外の整数型が ターゲット型 である場合、元の の値を ターゲット型 で表現できるなら値は変更されません。それ以外の場合、結果の値は未指定です。
(C++20まで)
  • ターゲット型 が整数型である場合、結果は列挙型の基底となる型への変換、およびその後の ターゲット型 への変換と同じになります。
(C++20以降)
  • ターゲット型 が浮動小数点型である場合、結果は元の値から ターゲット型 への変換と同じになります。
(C++11以降)
b) 整数型または列挙型の値は、任意の完全な列挙型に変換できます。
  • ターゲット型 が固定された基底型を持つ場合、 は、必要であれば 整数昇格 または 整数変換 によってまずその型に変換され、その後 ターゲット型 に変換されます。
  • ターゲット型 が固定された基底型を持たない場合、元の値が 列挙値の範囲内 にある場合は の値は変更されませんが、それ以外の場合は動作は未定義です。
c) 浮動小数点型の値も、任意の完全な列挙型に変換できます。結果は、 の元の値をまず ターゲット型 の基底となる型に 変換 し、その後 ターゲット型 自身に変換するのと同じです。
d) 浮動小数点型の prvalue は、他の任意の浮動小数点型に明示的に変換できます。
  • のソース値が ターゲット型 で正確に表現できる場合、値は変更されません。
  • それ以外の場合、 のソース値が ターゲット型 の 2 つの表現可能な値の間にある場合、変換の結果はそれらの値のいずれかの実装定義の選択となります。[2]
  • それ以外の場合、動作は未定義です。
(C++23から)
e) "cv1 Base へのポインタ" 型の 右辺値(C++11 まで)prvalue(C++11 以降) は、以下のすべての条件が満たされる場合、"cv2 Derived へのポインタ" 型に明示的に変換できます。
  • Derived は完全なクラス型である。
  • BaseDerived の基底クラスである。
  • cv1cv2 よりも限定された cv 修飾ではない。
ヌルポインタ値 である場合、結果は ターゲット型 のヌルポインタ値になります。それ以外の場合、結果は が指す Base 型のオブジェクトを包含する Derived 型のオブジェクトへのポインタになります。
以下のいずれかの条件が満たされる場合、プログラムは不正形式です。
  • BaseDerived仮想基底クラス である。
  • BaseDerived の仮想基底クラスの基底クラスである。
  • "ポインタから Derived" から "ポインタから Base" への有効な標準変換が存在しない。
がヌルポインタ値ではなく、実際には Derived 型のオブジェクトの基底クラスサブオブジェクトを指していない場合、動作は未定義です。
f) "Derived のメンバー、型 cv1 T へのポインタ" 型の 右辺値(C++11 まで)prvalue(C++11 以降) は、以下のすべての条件が満たされる場合、"Base のメンバー、型 cv2 T へのポインタ" 型に明示的に変換できます。
  • Derived は完全なクラス型である。
  • BaseDerived の基底クラスである。
  • cv1cv2 よりも限定された cv 修飾ではない。
がヌルメンバポインタ値である場合、結果は ターゲット型 のヌルメンバポインタ値になります。それ以外の場合、結果はクラス Base の元の (場合によっては間接的な) メンバーへのポインタになります。
"Base のメンバー、型 T へのポインタ" から "Derived のメンバー、型 T へのポインタ" への有効な標準変換が存在しない場合、プログラムは不正形式です。
がヌルメンバポインタ値ではなく、それが示すメンバーがクラス Base の (場合によっては間接的な) メンバーでない場合、動作は未定義です。
g) "cv1 void へのポインタ" 型の 右辺値(C++11 まで)prvalue(C++11 以降) は、T がオブジェクト型であり、かつ cv1cv2 よりも限定された cv 修飾ではない場合、"cv2 T へのポインタ" 型に明示的に変換できます。
  • がヌルポインタ値である場合、結果は ターゲット型 のヌルポインタ値になります。
  • がメモリ内の バイト のアドレス A を表し、かつ ATアライメント 要件を満たす場合、結果のポインタ値も A を表します。
  • 上記以外のそのようなポインタ変換の結果は未指定です。
  • が "cv3 T へのポインタ" 型からの以前の変換の結果である場合、結果は元の値になります。
(C++17まで)
  • がメモリ内の バイト のアドレス A を表すが、ATアライメント 要件を満たさない場合、結果のポインタ値は未指定です。
  • それ以外の場合、 がオブジェクト a を指し、かつ、aポインタ相互変換可能な型 T のオブジェクト b (cv 修飾を無視) が存在する場合、結果は b へのポインタになります。
  • それ以外の場合、ポインタ値は変換によって変更されません。
(C++17以降)

すべてのキャスト式と同様に、結果は次のようになります。

  • ターゲット型がlvalue参照型である場合、または関数型へのrvalue参照である場合、lvalueになります (C++11以降)
  • ターゲット型がオブジェクト型へのrvalue参照である場合、xvalueになります。
(C++11以降)
  • それ以外の場合はprvalueになります。
  1. この種類の static_cast は、std::move でムーブセマンティクスを実装するために使用されます。
  2. IEEE 算術演算がサポートされている場合、丸めはデフォルトで最近接になります。

[編集] ポインタ相互変換可能なオブジェクト

2 つのオブジェクト ab は、以下の場合に ポインタ相互変換可能 となります。

  • それらが同じオブジェクトである場合、または
  • 一方が共用体オブジェクトであり、他方がそのオブジェクトの非静的データメンバーである場合、または
  • 一方が 標準レイアウト クラスオブジェクトであり、他方がそのオブジェクトまたはそのオブジェクトの任意の基底クラスサブオブジェクトの最初の非静的データメンバーである場合、または
  • オブジェクト c が存在し、ac がポインタ相互変換可能であり、かつ cb がポインタ相互変換可能である場合。
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));

[編集] キーワード

static_cast

[編集]

#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]

[編集] 関連項目

English 日本語 中文(简体) 中文(繁體)