2011-08-23 9 views
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); 
    } 

私は驚いて

 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)’ 

をGCC 4.4.5 G ++ -c v.cpp を使用してコンパイルしますが得られませんことベースクラスgsl_vector_viewは、useVector(Vector)の呼び出しによって考慮されます。私はuseVectorが "The C++ Programming Language"、第3章、p。その保護された情報にアクセスすることができず、したがって、それによって混乱することはありません。 私は知りませんでした何を(正直に、そして、どちらか理解していない)私は

explicit Vector (const gsl_vector_view view); 

としてコンストラクタを宣言することにより、あいまいさを取り除くことができることを知って、ときに私オーバーロードされたコールのあいまいさがなくなるということです

Vector (const gsl_vector_view& view); 

というように、コンストラクタを宣言します。つまり、私は何となく適切なやり方だと考えています。

+0

+1、これは 'protected'継承とは関係ありません。そのように質問を再フォーマットする。 – iammilind

+0

btw。参照を取るためにuseVectorを宣言するとあいまいさがなくなります – PlasmaHH

答えて

4

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

オーバーロードの解像度は、標準の第13.3章で説明しています。私の解釈は、const AutoVector ovVector (const Vector& original);にバインドすることは、ユーザー定義の変換派生 - ベース変換([13.3.3.1.4/1])種類です。 Vector (const gsl_vector_view view);については、ユーザ定義変換に続いて左端から右端への変換であるため、変換シーケンスもユーザ定義変換です。したがって、両方の変換シーケンスは等しいとみなされ、どちらも他よりも優れていないため、あいまいさが発生します。もしVector (const gsl_vector_view& view);にCTORを変更する場合

次に、両方の変換は、ユーザー定義の変換(派生 - ベースの変換)続い左辺ツー値変換です。これらの2つを注文することができます([13.3.3.2/4])。const Vector&への変換はより良いと考えられ、したがってあいまいさはありません。

1

質問は、protected継承またはコンストラクタなどとは関係ありません。この問題は通常の関数呼び出しでも(どのような継承でも)持続します。

すべてのオーバーロードバージョンで参照渡しする場合は、最も近いベースクラスが選択されます(最も近くにあるベースクラスが1つ以上ある場合は、それが形成されます)。

値渡しの場合、すべての関数は同様に良好な候補とみなされます。したがって、このコンパイルエラーが発生しています。あなたの質問に多少一致する標準からの引用の小さな通路があります。

§13.3.1(5)
... ref-qualifierなしで宣言された非スタティックメンバ関数の場合、追加規則が適用されます。 - 暗黙の オブジェクトパラメータがconst修飾されていなくても、rvalueは パラメータにバインドできます。引き数は を暗黙オブジェクト・パラメーターのタイプに変換することができます。

関連する問題