3

次のコード スニペットがあります。

struct T {
    T(const T&) = default;
    T(const S &);
};

struct S {
    operator T();
};

int main() {
    S s;
    T t = s; // copy-initialization of class type
    return 0;
}

私の質問は、初期化があいまいであるというエラーを報告するのではなく、コンパイラが t の初期化に S::operator T() を好む理由です。私の意見では、次のことが起こります(間違っている場合は修正してください):

  • t は型 S の左辺値でコピー初期化されます
  • S は T ではなく、S も T のサブクラスではないため、S と T は無関係です。
  • 変数 t がコピー初期化され、型 S と T が無関係であるため、コンパイラは初期化を行うためにユーザー定義の変換シーケンスを見つけようとします。
  • オーバーロードの解決は、T の変換コンストラクターまたは S の変換関数のいずれかである可能性がある、最適なユーザー定義の変換を選択する責任があります。
  • 引数 s からのコンストラクター T::T(const S&) の暗黙的な変換シーケンスは恒等変換です。これは、左辺値 s がこの左辺値参照に直接バインドできるためです。
  • 引数 s からの変換関数 S::operator T() の暗黙的な変換シーケンスも恒等変換です。これは、暗黙的なオブジェクト パラメーターが S&

コンストラクターと変換関数の両方が、変数 t を直接初期化するために使用できる T 型の prvalue を返します。これは、両方のユーザー定義変換シーケンスの 2 番目の標準変換シーケンスが恒等変換であることを意味します。

これは、両方のユーザー定義変換シーケンスが同等に優れていることを意味します。または、変換関数を優先する特別なルールはありますか?

私はC++ 11標準で次のルールを読んでいました:

T x = a; の形式で発生する初期化。引数の受け渡し、関数の戻り、例外のスロー (15.1)、例外の処理 (15.3)、および集約メンバーの初期化 (8.5.1) と同様に、コピー初期化と呼ばれます。

初期化子のセマンティクスは次のとおりです...宛先の型が(おそらくcv修飾された)クラス型である場合: 初期化が直接初期化である場合、またはソース型のcv非修飾バージョンであるコピー初期化である場合宛先のクラスと同じクラス、またはその派生クラスである場合、コンストラクターが考慮されます....それ以外の場合 (つまり、残りのコピー初期化の場合)、ソース型から変換できるユーザー定義の変換シーケンス目的の型または (変換関数が使用されている場合) その派生クラスへの変換は、13.3.1.4 で説明されているように列挙され、オーバーロード解決 (13.3) によって最適なものが選択されます。

ユーザー定義の変換シーケンス U1 は、同じユーザー定義の変換関数またはコンストラクターを含み、U1 の 2 番目の標準変換シーケンスが U2 の 2 番目の標準変換シーケンスよりも優れている場合、別のユーザー定義の変換シーケンス U2 よりも優れた変換シーケンスです。

たぶん私は間違った仮定をしています。あなたが私を助けてくれることを願っています!

4

2 に答える 2

0

これを明確にするルールを見つけたと思います:

13.3.3.2: ... S1 と S2 は参照バインディング (8.5.3) であり、参照が参照する型は、トップレベルの cv 修飾子を除いて同じ型であり、参照が S2 によって初期化される型です。 refer は、S1 によって初期化された参照が参照する型よりも cv 修飾されています。

メンバー関数 S::operator T() では、暗黙的なオブジェクト パラメーターは、型 S の左辺値 s に直接バインドされる型 S& を持ちます。コンストラクター T::T(const S&) では、パラメーターは左辺値 s に直接バインドされます。 S 型ですが、この参照バインディングは演算子関数よりも cv 修飾されているため、オーバーロードの解決では演算子関数が優先されます。

これに同意しますか?

于 2013-09-04T23:25:13.500 に答える