Namespaces
Variants

User-defined conversion function

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」を「目次」に翻訳 - C++関連の用語(Syntax, Explanation, Keywords, Defect reports)は原文のまま保持 - HTMLタグ、属性、構造は完全に保持 - 番号部分は変更なし

構文

変換関数は、パラメータを持たず、明示的な戻り値の型がなく、以下の形式の名前を持つ 非静的メンバ関数 またはメンバ 関数テンプレート として宣言されます:

operator conversion-type-id (1)
explicit operator conversion-type-id (2) (C++11以降)
explicit ( expression ) operator conversion-type-id (3) (C++20以降)
1) すべての 暗黙的 および 明示的変換 に参加するユーザー定義変換関数を宣言します。
2) ユーザー定義変換関数を宣言し、 direct-initialization および explicit conversions のみに参加する。
3) 条件付きで explicit となるユーザー定義変換関数を宣言します。

conversion-type-id type-id ですが、その宣言子では関数および配列演算子 [] または () は許可されません(したがって、配列へのポインタなどの型への変換には、型エイリアス/typedefまたはidentityテンプレートが必要です:以下を参照)。typedefに関わらず、 conversion-type-id は配列型または関数型を表すことはできません。

ユーザ定義変換関数の宣言では戻り値の型は許可されませんが、 宣言文法 decl-specifier-seq は存在してもよく、 type-specifier またはキーワード static 以外の任意の指定子を含むことができます。特に、 explicit に加えて、指定子 inline virtual constexpr (C++11以降) consteval (C++20以降) 、および friend も許可されます( friend は修飾名を必要とすることに注意してください: friend A :: operator B ( ) ; )。

このようなメンバ関数がクラスXで宣言されると、Xから conversion-type-id への変換を実行します:

struct X
{
    // 暗黙の変換
    operator int() const { return 7; }
    // 明示的な変換
    explicit operator int*() const { return nullptr; }
    // エラー: 変換型IDで配列演算子は許可されていません
//  operator int(*)[3]() const { return nullptr; }
    using arr_t = int[3];
    operator arr_t*() const { return nullptr; } // typedef経由であればOK
//  operator arr_t () const; // エラー: いかなる場合も配列への変換は許可されません
};
int main()
{
    X x;
    int n = static_cast<int>(x);   // OK: nを7に設定
    int m = x;                     // OK: mを7に設定
    int* p = static_cast<int*>(x); // OK: pをnullに設定
//  int* q = x; // エラー: 暗黙の変換はありません
    int (*pa)[3] = x;  // OK
}

説明

ユーザー定義変換関数は、 暗黙変換 の第二段階で呼び出されます。この段階は、0個または1個の 変換コンストラクタ または0個または1個のユーザー定義変換関数で構成されます。

変換関数と変換コンストラクタの両方がユーザー定義変換の実行に使用可能な場合、 オーバーロード解決 において、 コピー初期化 および 参照初期化 の文脈では変換関数とコンストラクタの両方が考慮されますが、 直接初期化 の文脈ではコンストラクタのみが考慮されます。

struct To
{
    To() = default;
    To(const struct From&) {} // 変換コンストラクタ
};
struct From
{
    operator To() const {return To();} // 変換関数
};
int main()
{
    From f;
    To t1(f);  // 直接初期化: コンストラクタを呼び出す
    // 注: 変換コンストラクタが利用できない場合、暗黙的なコピーコンストラクタが
    // 選択され、変換関数がその引数を準備するために呼び出される
//  To t2 = f; // コピー初期化: 曖昧
    // 注: 変換関数が非const型からの場合(例: From::operator To();)、
    // このケースではコンストラクタの代わりにそれが選択される
    To t3 = static_cast<To>(f); // 直接初期化: コンストラクタを呼び出す
    const To& r = f;            // 参照初期化: 曖昧
}

自身の(おそらくcv修飾された)クラス(またはその参照)への変換、自身のクラスの基底クラス(またはその参照)への変換、および型 void への変換関数は定義可能ですが、変換シーケンスの一部として実行することはできません。ただし、一部の場合において virtual ディスパッチを通じて実行される場合を除きます:

struct D;
struct B
{
    virtual operator D() = 0;
};
struct D : B
{
    operator D() override { return D(); }
};
int main()
{
    D obj;
    D obj2 = obj; // D::operator D() を呼び出さない
    B& br = obj;
    D obj3 = br;  // 仮想ディスパッチを通じて D::operator D() を呼び出す
}

メンバ関数呼び出し構文を使用して呼び出すこともできます:

struct B {};
struct X : B
{
    operator B&() { return *this; };
};
int main()
{
    X x;
    B& b1 = x;                  // X::operatorB&() を呼び出さない
    B& b2 = static_cast<B&>(x); // X::operatorB& を呼び出さない
    B& b3 = x.operator B&();    // X::operatorB& を呼び出す
}

変換関数を明示的に呼び出す際、 conversion-type-id は貪欲です:これは conversion-type-id を形成できる可能性のある最長のトークン列です (属性を含む場合あり) (C++11以降)

& x.operator int * a; // エラー: & (x.operator int*) a として解析される
                      //           & (x.operator int) * a としては解析されない
operator int [[noreturn]] (); // エラー: noreturn属性が型に適用されている

プレースホルダー auto conversion-type-id で使用でき、 推論された戻り値の型 を示します:

struct X
{
    operator int(); // OK
    operator auto() -> short; // error: trailing return type not part of syntax
    operator auto() const { return 10; } // OK: deduced return type
    operator decltype(auto)() const { return 10l; } // OK: deduced return type
};

注意: 変換関数テンプレート は推論された戻り値の型を持つことは許可されていません。

(C++14以降)

変換関数は継承可能であり、 virtual にできますが、 static にはできません。派生クラスの変換関数は、同じ型への変換でない限り、基底クラスの変換関数を隠蔽しません。

変換関数はテンプレートメンバ関数として定義することができます。例えば、 std::auto_ptr<T>::operator auto_ptr<Y> などです。適用される特別な規則については、 メンバーテンプレート および テンプレート引数推論 を参照してください。

キーワード

operator

不具合報告

以下の動作変更の欠陥報告書は、以前に公開されたC++規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
CWG 296 C++98 変換関数はstaticにできた staticで宣言できない
CWG 2016 C++98 変換関数は戻り値の型を指定できなかったが、
型は conversion-type-id 内に存在する
変換関数の宣言指定子では
戻り値の型を指定できない
CWG 2175 C++11 [ [ noreturn ] ]
operator int [ [ noreturn ] ] ( ) ; において
noptr-declarator (関数宣言子)の一部として解析されるか、
conversion-type-id の一部として解析されるか不明確だった
conversion-type-id の一部として
解析される