ユーザー定義変換関数
クラス型から別の型への暗黙的な変換または明示的な変換を可能にします。
目次 |
[編集] 構文
変換関数は、非静的メンバ関数またはメンバ関数テンプレートとして宣言され、パラメータがなく、明示的な戻り型がなく、以下の形式の名前を持ちます。
operator conversion-type-id |
(1) | ||||||||
explicit operator conversion-type-id |
(2) | (C++11以降) | |||||||
explicit ( expression ) operator conversion-type-id |
(3) | (C++20以降) | |||||||
conversion-type-id は型IDですが、関数および配列演算子 [] または () はその宣言子で許可されません(したがって、配列へのポインタなどの型への変換には、型エイリアス/typedefまたは同一テンプレートが必要です。下記を参照)。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 { // implicit conversion operator int() const { return 7; } // explicit conversion explicit operator int*() const { return nullptr; } // Error: array operator not allowed in conversion-type-id // operator int(*)[3]() const { return nullptr; } using arr_t = int[3]; operator arr_t*() const { return nullptr; } // OK if done through typedef // operator arr_t () const; // Error: conversion to array not allowed in any case }; int main() { X x; int n = static_cast<int>(x); // OK: sets n to 7 int m = x; // OK: sets m to 7 int* p = static_cast<int*>(x); // OK: sets p to null // int* q = x; // Error: no implicit conversion int (*pa)[3] = x; // OK }
[編集] 解説
ユーザー定義変換関数は、暗黙的な変換の第2段階で呼び出されます。この第2段階は、0個または1個の変換コンストラクタ、または0個または1個のユーザー定義変換関数で構成されます。
変換関数と変換コンストラクタの両方が何らかのユーザー定義変換を実行できる場合、コピー初期化および参照初期化のコンテキストでは、変換関数とコンストラクタの両方がオーバーロード解決によって考慮されますが、直接初期化のコンテキストではコンストラクタのみが考慮されます。
struct To { To() = default; To(const struct From&) {} // converting constructor }; struct From { operator To() const {return To();} // conversion function }; int main() { From f; To t1(f); // direct-initialization: calls the constructor // Note: if converting constructor is not available, implicit copy constructor // will be selected, and conversion function will be called to prepare its argument // To t2 = f; // copy-initialization: ambiguous // Note: if conversion function is from a non-const type, e.g. // From::operator To();, it will be selected instead of the ctor in this case To t3 = static_cast<To>(f); // direct-initialization: calls the constructor const To& r = f; // reference-initialization: ambiguous }
自身の(cv修飾された可能性のある)クラス(またはそれへの参照)、自身のクラスの基底クラス(またはそれへの参照)、および型 void への変換関数は定義できますが、いくつかのケースを除き、仮想ディスパッチを介して変換シーケンスの一部として実行することはできません。
struct D; struct B { virtual operator D() = 0; }; struct D : B { operator D() override { return D(); } }; int main() { D obj; D obj2 = obj; // does not call D::operator D() B& br = obj; D obj3 = br; // calls D::operator D() through virtual dispatch }
メンバ関数呼び出し構文を使用して呼び出すこともできます。
struct B {}; struct X : B { operator B&() { return *this; }; }; int main() { X x; B& b1 = x; // does not call X::operatorB&() B& b2 = static_cast<B&>(x); // does not call X::operatorB& B& b3 = x.operator B&(); // calls X::operatorB& }
変換関数を明示的に呼び出す場合、conversion-type-id は貪欲です。これは、conversion-type-id を形成する可能性のあるトークンの最長シーケンスです(属性がある場合も含む)(C++11以降)
& x.operator int * a; // error: parsed as & (x.operator int*) a, // not as & (x.operator int) * a operator int [[noreturn]] (); // error: noreturn attribute applied to a type
|
プレースホルダー 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以降) |
変換関数は継承可能であり、仮想にできますが、静的にはできません。派生クラスの変換関数は、基底クラスの変換関数と同じ型に変換する場合を除き、基底クラスの変換関数を隠蔽しません。
変換関数は、テンプレートメンバ関数にできます。たとえば、std::auto_ptr<T>::operator auto_ptr<Y>。適用される特殊な規則については、メンバテンプレートおよびテンプレート引数推論を参照してください。
[編集] キーワード
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 296 | C++98 | 変換関数は静的になりうる | 静的に宣言できない |
| CWG 2016 | C++98 | 変換関数は戻り型を指定できなかったが、 型は conversion-type-id に存在する |
戻り型は 変換関数の宣言指定子で指定できない |
| CWG 2175 | C++11 | [[noreturn]] が operator int [[noreturn]] (); の一部として noptr-declarator(関数宣言子)として解析されるのか、conversion-type-id として解析されるのか不明確だった。 |
それは conversion-type-id の一部として解析される |