User-defined conversion function
暗黙変換 または 明示的変換 を クラス型 から他の型へ有効にします。
目次 |
構文
変換関数は、パラメータを持たず、明示的な戻り値の型がなく、以下の形式の名前を持つ 非静的メンバ関数 またはメンバ 関数テンプレート として宣言されます:
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
は
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>
などです。適用される特別な規則については、
メンバーテンプレート
および
テンプレート引数推論
を参照してください。
キーワード
不具合報告
以下の動作変更の欠陥報告書は、以前に公開された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
の一部として
解析される |