Namespaces
Variants

static_cast conversion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

目次

翻訳のポイント: - 「Contents」を「目次」に翻訳 - HTMLタグ、属性、class名などは一切変更せず保持 - C++関連の用語(Syntax、Explanation、Pointer-interconvertible objects、Notes、Keywords、Example、Defect reports、References、See also)は翻訳せず原文のまま保持 - 数字や構造は完全に維持 - プロフェッショナルな技術文書としての正確性を確保

構文

static_cast< target-type  >( expression  )
HTMLタグ、属性、および` `タグ内のC++固有の用語(`static_cast`)は翻訳せず、元のフォーマットを保持しました。

target-type 型の値を返します。

説明

以下の変換のみが static_cast で実行可能です( const性の除去 (またはvolatile性)を行う場合を除く)。

1) expression が「 cv1 Base 」型のlvalueであり、かつ target-type が「 cv2 Derived への参照」である場合、以下の条件がすべて満たされるとき、結果は expression を包含する Derived 型のオブジェクトを参照する:
  • Derived は完全なクラス型である。
  • Base Derived の基底クラスである。
  • cv1 cv2 よりも強いCV修飾ではない。
以下のいずれかの条件が満たされる場合、プログラムは不適格となります:
  • Base Derived 仮想基本クラス である場合。
  • Base Derived の仮想基本クラスの基本クラスである場合。
  • Derived へのポインタ」から「 Base へのポインタ」への有効な 標準変換 が存在しない場合。
expressionが実際に 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 の型のアクセス不可能または曖昧な基底クラスである場合、プログラムは不適格である。
expression bit-field 左辺値である場合、まず基底型のprvalueに変換される。
(since C++11)
4) target-type が(CV修飾されている可能性のある) void の場合、変換には結果がありません。この場合、 expression discarded-value expression です。
5) それ以外の場合、 expression target-type に明示的に変換できる。ただし、

宣言 target-type temp ( expression  ) ; が、ある発明された一時変数 temp に対して適正である場合。

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

(C++17まで)

以下のいずれかの条件が満たされる場合:

  • expression から target-type への暗黙変換シーケンスが存在する。
  • expression からの型 target-type のオブジェクトまたは参照の オーバーロード解決 で、 直接初期化 のための少なくとも1つの有効な関数が見つかる。
  • target-type が最初の要素 x を持つ 集成体型 であり、 expression から x の型への暗黙変換シーケンスが存在する。
(C++20以降)

明示的変換は以下のように定義される:

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

すべてのキャスト式と同様に、結果は次のとおりです:

  • target-type が左辺値参照型の場合(または関数型への右辺値参照の場合 (C++11以降) )、左辺値となる;
  • target-type がオブジェクト型への右辺値参照の場合、xvalueとなる;
(C++11以降)
  • それ以外の場合は prvalue。
  1. この種の static_cast std::move におけるムーブセマンティクスの実装に使用されます。
  2. 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));

キーワード

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. 静的ダウンキャスト
    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]

関連項目