変換関数が使用される場合と使用されない場合のいくつかのランダムな状況は次のとおりです。
まず、変換関数は、同じクラス型または基本クラス型への変換には使用されないことに注意してください。
引数渡し時の変換
引数の受け渡し中の変換では、コピーの初期化の規則が使用されます。これらのルールは、参照に変換するかどうかに関係なく、変換関数のみを考慮します。
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
引数の受け渡しは、コピーの初期化の 1 つのコンテキストにすぎません。もう 1 つは、コピー初期化構文を使用した「純粋な」形式です。
B b = A(); // called!
参照への変換
条件演算子では、変換後の型が左辺値の場合、参照型への変換が可能です。
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
参照への別の変換は、参照を直接バインドする場合です。
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
関数ポインタへの変換
関数ポインターまたは参照への変換関数があり、呼び出しが行われると、それが使用される場合があります。
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
このことは、実際には非常に役立つ場合があります。
非クラス型への変換
いつでもどこでも発生する暗黙の変換は、ユーザー定義の変換も使用できます。ブール値を返す変換関数を定義できます
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(この場合の bool への変換は、他の整数型への変換を禁止するために、safe-bool イディオムによってより安全にすることができます。) 変換は、組み込み演算子が特定の型を期待する場所ならどこでもトリガーされます。ただし、変換が邪魔になる場合があります。
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
メンバーの場合は 2 番目のパラメーターに変換が必要であり、組み込み演算子の場合は最初のパラメーターにユーザー定義の変換が必要なため、呼び出しがあいまいになる可能性があります。他の 2 つのパラメーターはそれぞれ完全に一致します。場合によっては、呼び出しがあいまいになることはありません (そのときとはptrdiff_t
異なる必要がありますint
)。
変換関数テンプレート
テンプレートにはいくつかの優れた機能がありますが、それらについては十分に注意してください。次の例では、型を任意のポインター型に変換できます (メンバー ポインターは "ポインター型" とは見なされません)。
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();