5

私は GSL のいくつかの部分に小さな C++ ラッパーを書き、次のパズルに遭遇しました (私にとって)。コードは次のとおりです (要点のみに縮小)。

    #include <stdlib.h>
    struct gsl_vector_view {};

    class Vector : protected gsl_vector_view {
            public:
            Vector ( const Vector& original );
            Vector ( const gsl_vector_view view );
    };

    class AutoVector : public Vector {
            public:
            explicit AutoVector ( const size_t dims );
    };

    void useVector ( const Vector b ) {}

    void test () {
            const AutoVector ov( 2 );
            useVector( ov );
    }

gcc 4.4.5 g++ -c v.cpp を使用してコンパイルされませんが、生成されます

     In function ‘void test()’:
    19: error: call of overloaded ‘Vector(const AutoVector&)’ is ambiguous
    7: note: candidates are: Vector::Vector(gsl_vector_view)
    6: note:                 Vector::Vector(const Vector&)
    19: error:   initializing argument 1 of ‘void useVector(Vector)’

保護された基底クラス gsl_vector_view が useVector( Vector ) の呼び出しで考慮されていることに驚きました。useVector は、「The C++ Programming Language」、3rd e.、p. 405 であるため、その保護された情報にアクセスできないため、混乱することはありません。コンストラクターを次のように宣言することで、あいまいさを取り除くことができることを知っています

    explicit Vector ( const gsl_vector_view view );

私が知らなかった (正直なところ、どちらも理解していない) ことは、コンストラクターを次のように宣言すると、オーバーロードされた呼び出しのあいまいさがなくなることです。

    Vector ( const gsl_vector_view& view );

つまり、参照によって引数を渡します(とにかく、これは適切な方法だと思います)。

4

2 に答える 2

4

アクセス チェックの前にオーバーロードの解決が行われるため、保護された基本クラスのメンバーも考慮されます。

オーバーロードの解決については、標準の 13.3 章で説明されています。私の解釈では、バインディングはconst AutoVector ovユーザー定義の変換であり、派生からベースへの変換([13.3.3.1.4/1]) の種類です。の場合、左辺値から右辺値への変換の後にユーザー定義の変換が続くため、変換シーケンスもユーザー定義の変換です。したがって、両方の変換シーケンスは等しいと見なされ、どちらも他よりも優れているわけではないため、あいまいさが生じます。Vector ( const Vector& original );Vector ( const gsl_vector_view view );

ここで、ctor を に変更するとVector ( const gsl_vector_view& view );、両方の変換が左辺値から値への変換であり、その後にユーザー定義の変換 (派生から基底への変換) が続きます。これらの 2 つは順序付けることができ ([13.3.3.2/4])、への変換のconst Vector&方が優れていると見なされるため、あいまいさはありません。

于 2011-08-23T08:30:35.070 に答える
1

protected問題は、継承やコンストラクター自体とは関係ありません。この問題は、通常の関数呼び出しでも(継承が何であれ)持続します。

すべてのオーバーロードバージョンで参照を渡す場合、最も近い基本クラスが選択されます(最も近い基本クラスが複数ある場合は、形式が正しくありません)。

値渡しの場合、すべての関数が同等に適切な候補と見なされます。したがって、このコンパイルエラーが発生します。標準からの引用の小さな一節がありますが、これはあなたの質問にいくらか一致します。

§13.3.1(5)
... ref-qualifierなしで宣言された非静的メンバー関数の場合、追加のルールが適用されます。—暗黙のオブジェクトパラメーターがconst修飾されていない場合でも、右辺値をパラメーターにバインドできます。他のすべての点で、引数を暗黙のオブジェクトパラメータの型に変換できる限り。

于 2011-08-23T09:32:40.080 に答える