13

Follow-up question to this one.

Basically, in the following code, why does the compiler think that the B inside A<B> in Cs constructor refer to the (inaccessible) constructor of the B base class?

struct B{};

template <typename T>
struct A : private T{};

struct C : public A<B>{                                                                             
    C(A<B>);   // ERROR HERE
};

Live example on Ideone. Output:

prog.cpp:1:9: error: 'struct B B::B' is inaccessible
prog.cpp:7:7: error: within this context

Note that the same error pops up if you change the constructor argument to A<B*>, A<B&> or even A<const B>. Also note that three of MSVC10, GCC 4.7 and Clang 3.1 ToT will error out, so it must be something in the C++ spec. What is it?

Community
  • 1
  • 1
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • I don't know why you created the exact same topic! You could have edited that topic to make that a better one. – Nawaz Feb 10 '12 at 06:07
  • 3
    @Nawaz: It's fundamentally a different question. I ask "why", the other question asks "what to do". – Xeo Feb 10 '12 at 06:10
  • Man, I've been bitten by this more than once with `class A : private NotCopyable { class B : private NotCopyable {} };`. I guess it looks up symbols in the class scope before looking at the global scope. – André Caron Feb 10 '12 at 06:11
  • @Xeo: That is why I said *you could have edited that topic to make that a better one.* – Nawaz Feb 10 '12 at 06:11
  • @AndréCaron: That particular example compiles fine. – Xeo Feb 10 '12 at 06:13
  • @Xeo: yes indeed since `B` has access to `A`'s privates. I can't remember what the exact code sample was, but it was the same problem where using the type name of a private base class was messing up things. – André Caron Feb 10 '12 at 06:16
  • @Xeo: just remembered. Something along the lines of `A` inherits `NotCopyable`, `B` inherits `A` and `B::C` inherits `NotCopyable`. – André Caron Feb 10 '12 at 06:18

1 Answers1

15

The standard allows injected class names to be less accessible than the original names. This is even mentioned in a note in §11.1/5, together with an example:

[ Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. —end note ]

[ Example:

class A { };
class B : private A { };
class C : public B {
  A *p; // error: injected-class-name A is inaccessible
  ::A *q; // OK
};

end example ]

Accessing A unqualified uses the injected name, which is not accessible because it comes from private inheritance. Accessing A qualified uses the declared name, which is accessible in the global scope.

Community
  • 1
  • 1
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510