From [class.access]/7 we have the following sentence:
Similarly, the use of
A::B
as a base-specifier is well-formed becauseD
is derived fromA
, so checking of base-specifiers must be deferred until the entire base-specifier-list has been seen.
class A {
protected:
struct B { };
};
struct D: A::B, A { };
See live example with clang. As a matter of fact, clang also complains about this snippet, where no deferment is necessary.
class A {
protected:
struct B { };
};
struct D: A, A::B { };
Why does this code not compile?
PS: gcc and VS21013 don't compile the codes either.
I believe this to be a bug with clang. Ideone doesn't accept the code either: http://ideone.com/uiFl9L:
I checked with gcc-5.1.0, gcc-4.9 and clang-3.7(rc2). The standard explicitly states this as well-formed (see question) thus the compilers are at fault.
The example clearifies [class.access]/6:
This means, according to [class.access]/2 that a class has access to all base-classes, even before they are declared.
This is simply a compiler bug. The normative text of the standard supports the example. The fact that multiple compilers have the same bug means this is part of the standard is tricky to get right.
There are open bugs about this for GCC and for clang. Note that a few related cases are actually subtle differences between C++03 and C++11, but as far as I can tell, not this one.
[class.access]/1.2 merely states
and 11.4 does not expand on this. You are using the name
B
in a classD
derived from that classA
. That's fine.