Hériter d'un constructeur d'une classe de modèle privée en C ++
Pourquoi la classe D
compile-t-elle, mais pas la classe 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
};
J'ai testé avec GCC, Clang et Visual C ++, et ils sont tous identiques. Changer class B : private T
pour public T
résoudre le problème. Mais pourquoi? (Notez que le using T::T
est public
.)
La classe A
contient le nom de la classe injectée A
dans sa portée (c'est-à-dire qu'elle fait A::A
référence à la classe A
sauf si elle fait référence au constructeur).
La classe B
hérite de ceci, donc le nom A
dans la portée de B
fait référence au nom de classe injecté A
dans la portée de A
. Cependant, comme A
est une classe de base privée de B
, tous les noms dans la portée de A
sont privés à l'intérieur B
.
La classe C
hérite à nouveau de cela, mais elle ne peut pas y accéder A
, car elle est privée à l'intérieur B
. D'où l'erreur. Notez que l'erreur provient en fait de l'utilisation du nom A
dans la construction B<A>
.
La classe BA
n'a pas ce problème, puisque la définition B<A>
n'est dans la portée d'aucune classe, donc le nom A
fait référence au nom global A
et non à un nom de classe injecté. Et bien sûr, le nom BA
est public.
Vous pouvez facilement résoudre ce problème en qualifiant le nom A
en C
:
class C : public B<A>
{
public:
C() : B<::A>( 123 ) {}
};
Notez que l'héritage du constructeur n'y a aucun effet. Le problème est avec l'accès au nom de la classeA
(injecté A
et hérité dans B
et C
), pas avec l'accès au constructeur.