[解決済み] C++で変換演算子はどのように動作するのですか?
質問
この簡単な例を考えてみましょう。
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
C++では変換演算子はどのように動作するのですか?(すなわち) コンパイラはいつ変換演算子の後に定義された型を代入しようとするのでしょうか?
どのように解決するのですか?
変換関数を使用する場合と使用しない場合のランダムな状況を以下に示します。
まず、変換関数は同じクラス型や基底クラス型への変換には決して使用されないことに注意してください。
引数渡し時の変換
引数渡し時の変換は、コピー初期化のルールが適用されます。これらのルールは、参照に変換するかどうかに関係なく、あらゆる変換関数を考慮するだけです。
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
引数の受け渡しは、コピー初期化の1つのコンテキストに過ぎません。もうひとつは、コピー初期化構文を使った "pure"形式です。
B b = A(); // called!
リファレンスへの変換
条件演算子では、変換先の型がlvalueの場合、参照型への変換が可能です。
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番目のパラメータに変換が必要で、組み込みオペレータについては、1番目のパラメータにユーザ定義の変換が必要だからです。他の2つのパラメータはそれぞれ完全に一致します。場合によっては、呼び出しがあいまいでないこともあります (
ptrdiff_t
とは異なる必要があります。
int
では)。
変換関数テンプレート
テンプレートはいくつかの素晴らしいことを可能にしますが、それについては非常に慎重であるべきです。以下は、ある型を任意のポインタ型に変換できるようにするものです(メンバポインタは"ポインタ型"とは見なされません)。
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
関連
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】 while(cin) と while(cin >> num) の違いは何ですか?)
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] Linux上で動作するC++コードのプロファイリングを行うにはどうすればよいですか?
-
[解決済み】静的定数文字列(クラスメンバ)
-
[解決済み】派生クラスでオーバーライドされた関数が、ベースクラスの他のオーバーロードを隠してしまうのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み】std::cin.getline( ) vs. std::cin
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)