17
class C {
public:
    C() { }
};

class B {
public:
    B(C c) { }
    B() { }
};

class A {
public:
    A(bool b) { }
    A(B b) { }
};

int main() {
    A a1 = true; // bool -> A        is allowed
    A a2 = B();  // B -> A           is allowed

    A a3 = 7;    // int -> bool -> A is allowed
    A a4 = C();  // C -> B -> A      isn't allowed
}

では 2 段階の暗黙的な変換をbool使用できるのに、 では使用できないのはなぜCですか? 多段階の暗黙的な変換を記述する一般的なルールは何ですか?

4

2 に答える 2

15

複数ステップのユーザー定義の暗黙的な変換はありません。

int -> bool -> A

int->bool変換はユーザー定義ではないため、許可されます。

12.3 変換 [class.conv]

1 クラス オブジェクトの型変換は、コンストラクタおよび変換関数によって指定できます。これらの変換はユーザー定義変換と呼ばれ、暗黙的な型変換 (節 4)、初期化 (8.5)、および明示的な型変換 (5.4、5.2.9) に使用されます。

2 ユーザー定義の変換は、明確な場合にのみ適用されます (10.2、12.3.2)。変換は、アクセス制御規則 (第 11 節) に従います。アクセス制御は、あいまいさの解決後に適用されます (3.4)。

3 [ 注: 関数呼び出しでの変換の使用の説明と以下の例については、13.3 を参照してください。—終わりのメモ]

4 最大 1 つのユーザー定義の変換 (コンストラクターまたは変換関数) が暗黙的に単一の値に適用されます。

于 2012-10-11T19:44:28.310 に答える
1

この構造は完全に合法であるため、

A a4((C()));

問題は、コピーの初期化を使用することです。本当に、あなたの例は次のようになります

A a4((A(C()));

8.5/16

初期化子のセマンティクスは次のとおりです。宛先の型は初期化されるオブジェクトまたは参照の型であり、ソースの型は初期化式の型です。初期化子が単一の (おそらく括弧で囲まれた) 式でない場合、ソースの型は定義されていません。

宛先の型が (おそらく cv 修飾された) クラス型の場合:

— それ以外の場合 (つまり、残りのコピー初期化の場合)、ソース型から宛先型、または (変換関数が使用されている場合) その派生クラスに変換できるユーザー定義の変換シーケンスは、13.3 で説明されているように列挙されます。 .1.4 であり、過負荷の解決 (13.3) によって最適なものが選択されます。

13.3.1.4/1

8.5 で指定された条件下では、クラス型のオブジェクトのコピー初期化の一部として、ユーザー定義の変換を呼び出して、初期化子式を初期化されるオブジェクトの型に変換できます。

オーバーロードの解決は、呼び出すユーザー定義の変換を選択するために使用されます。「cv1 T」が初期化されるオブジェクトの型であり、T がクラス型であると仮定すると、候補関数は次のように選択されます。 — T の変換コンストラクター (12.3.1) は候補関数です。

— 初期化式の型がクラス型「cv S」の場合、S とその基底クラスの非明示的な変換関数が考慮されます。

13.3.3.1/4

ただし、13.3.1.3 でクラスのコピー初期化の 2 番目のステップでテンポラリのコピー/移動のために呼び出されたときに候補となるコンストラクターまたはユーザー定義の変換関数の引数を考慮すると、13.3.1.7 で渡すときに単一の引数としての初期化子リスト、または初期化子リストに要素が 1 つだけあり、何らかのクラス X への変換または (おそらく cv 修飾された) X への参照が X のコンストラクターの最初のパラメーターと見なされる場合、または13.3.1.4によって、13.3.1.5、または 13.3.1.6 のいずれの場合も、標準の変換シーケンスと省略記号の変換シーケンスのみが考慮されます。

この場合、ユーザー定義の変換 (C -> B) は考慮されません。

于 2012-10-11T21:08:04.600 に答える