2016-08-23 9 views
46

クラスDはコンパイルされますが、クラスCはどうしてですか?C++のプライベートテンプレートクラスからコンストラクタを継承する

class A 
{ 
    public: 
     A(int) {} 
}; 

template <class T> 
class B : private T // Note: private base class 
{ 
    public: 
     using T::T; 
}; 

class C : public B<A> 
{ 
    public: 
     C() : B<A>(123) {} // Error: 'class A A::A' is inaccessible 
};       //   within this context 

using BA = B<A>; 

class D : public BA 
{ 
    public: 
     D() : BA(123) {} // OK 
}; 

私はGCC、ClangおよびVisual C++でテストし、それらはすべて同じです。 class B : private Tからpublic Tに変更すると問題が解決します。しかし、なぜ? (using T::Tpublicであることに留意されたい。)

+0

「テンプレート」タグを追加してホットショットをアタッチしました。 "tag spamming"の批判を私に教えてください。 – Bathsheba

+0

それはテンプレートタグを正当化し、実際にクラステンプレートの名前検索は微妙に異なります。 – MSalters

答えて

42

クラスAは、その範囲内に、注入クラス名Aを含有する(すなわち、コンストラクタを参照するために発生しない限り、A::AクラスAを指します)。

クラスB継承これを、そうBの範囲内の名前AAの範囲で注入クラス名Aを指します。ただし、AはプライベートベースクラスBであるため、Aのスコープ内のすべての名前はBの中でプライベートになります。

クラスCはこれを継承しますが、Bの中ではプライベートなので、Aにはアクセスできません。したがって、エラー。このエラーは、実際にはというコンストラクトでAという名前を使用していることに注意してください。定義B<A>は、任意のクラスのスコープ内にはないので名前Aは、任意の注入されたクラス名にグローバル名Aを参照しないよう

クラスBAは、この問題を持っていません。もちろん、BAという名前は公開されています。

あなたは簡単にCで名前Aを修飾することによってこの問題を解決することができます:コンストラクタの継承が影響を与えないことを

class C : public B<A> 
{ 
public: 
    C() : B<::A>(123) {} 
}; 

注意を。問題は、クラスの名前AAに注入され、BおよびCに継承されています)へのアクセスであり、コンストラクタへのアクセスではありません。

+1

それで、他の(劣った)用語では、エラーは、それが_wrong_名前空間(つまり、クラス 'B')で名前Aにアクセスしようとしているということです、間違っていますか? Chapeau。本当に面白いです。 – skypjack

+0

そのクラスのプライベートメンバーへのアクセス@skypjack –

+0

@skypjackはい、それです。それを置くもう一つの方法は、私的な、したがってアクセス不能なクラス名 'A'は(アクセス可能な)グローバル名' A'を隠すことです。 – Angew

関連する問題