Namespaces
Variants

Explicit type 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

明示的変換と暗黙的変換を組み合わせて型間の変換を行います。

目次

構文

( 型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以降)

任意の数の値をターゲット型の値に明示的に変換します。

1) 明示的な型変換(キャスト表記)、 C-style cast とも呼ばれる。
2-7) 明示的な型変換(関数表記)、別名 関数形式キャスト
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 を含む)

説明

1) Cスタイルキャストが検出されると、コンパイラは以下のキャスト式の順序で解釈を試みます:
a) const_cast < type-id  > ( unary-expression  ) ;
b) static_cast < type-id  > ( unary-expression  ) 、拡張機能として: 派生クラス へのポインタまたは参照は、基底クラスが アクセス不可能 であっても(つまり、このキャストはprivate継承指定子を無視する)、明確な基底クラスへのポインタまたは参照に追加でキャスト可能(逆も同様)。同じことが、明確な非仮想基底クラスのメンバへのポインタへの メンバへのポインタ のキャストにも適用される;
c) a static_cast (拡張機能付き)に続いて const_cast ;
d) reinterpret_cast < type-id  > ( unary-expression  ) ;
e) a reinterpret_cast followed by const_cast .
それぞれのキャスト演算子の要件を満たす最初の選択肢が、たとえ不適格であっても選択されます(例を参照)。もし static_cast に続いて const_cast が使用され、その変換が複数の方法で解釈可能な場合、その変換は不適格となります。
さらに、Cスタイルキャストは不完全なクラス型へのポインタから、不完全なクラス型へのポインタへ、および不完全なクラス型へのポインタ間でキャストできます。 type-id unary-expression の型が両方とも不完全なクラス型へのポインタである場合、 static_cast reinterpret_cast のどちらが選択されるかは未規定です。
2-7) 関数形式キャストは ( simple-type-specifier  または identifier  (C++11以降) )と 初期化子 (残りの部分)を指定し、対象型 T の値を構築します。 T は指定された型 と初期化子から決定されます (C++17以降) :

T は指定された型です。

(C++17以前)

T は以下のように決定されます:

  • 指定された型が推定されるクラス型のプレースホルダである場合、 T クラステンプレート引数推定 でオーバーロード解決によって選択された関数の戻り値の型です。
(C++23以降)
  • それ以外の場合、 T は指定された型です。
(C++17以降)
変換結果は以下のように決定されます:
  • 関数形式キャストが構文 (2) であり、括弧内に式が1つだけ存在する場合、このキャストは対応するC形式キャストと等価です。
  • それ以外の場合、 T が(cv修飾可能性のある) void の場合、結果は初期化を実行しない void 型の 右辺値 (C++11まで) 純粋右辺値 (C++11以降) です。
  • 初期化子が ( ) でない場合、プログラムは不適格です。
(C++11まで)
  • 初期化子が ( ) または { } でない場合( パック展開 後)、プログラムは不適格です。
(C++11以降)
  • それ以外の場合、 T が参照型の場合、関数形式キャストは型 T の仮想変数 t を指定された初期化子から 直接初期化 するのと同じ効果を持ち、結果は初期化された t です。
  • 結果は左辺値です。
(C++11まで)
  • T が左辺値参照型または関数型への右辺値参照の場合、結果は左辺値です。
  • それ以外の場合、結果は亡き値です。
(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 キャスト演算子