struct B {};
struct D : private B {
B* fun () { return new D; } // ok
}
struct DD : public D {
B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
};
This error seems unreasonable to me. If we can use simple B*
in global scope then why not in its privately derived classes? g++ demo.
We are Not trying to convert DD*
to B*
, which is forbidden by the language rules (this, this, this are related questions).
Note that, if I change B* foo()
to int foo()
, things go fine.
So apparently the compiler thinks B
is referring to the private constructor of B
rather than the type.
Qualifying B
apparently fixes that error:
class B* foo () { return 0; }
or this:
::B* foo () { return 0; }
I don't know why that's happening, but maybe this will help.
Update: maybe it's related to 11.2.4 of standard? The only problem is that my standardese isn't good enough to fully understand it.
(sorry for the image, copy/pasting isn't working for me)
A quick look-up for injected-class-name in the Standard yields:
§11.1 [class.access.spec]
5/ [ 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 ]
I believe this is eerily close to your example ;)
Note clang 3.0's stack, which is slightly more explicit:
$ clang++ -fsyntax-only test.cpp
test.cpp:6:5: error: 'B' is a private member of 'B'
B* foo () { return 0; } // error: ‘struct B B::B’ is inaccessible !
^
test.cpp:2:12: note: constrained by private inheritance here
struct D : private B {
^~~~~~~~~
test.cpp:1:8: note: member is declared here
struct B {};
^
1 error generated.
Here we see that B
is accessed through D
, instead of directly picked up in the global namespace.
My best guess is that it's not forbidden, C++ simply doesn't see the B type inside that statement or in better terms the label B
means nothing.
Some good read about
- http://eli.thegreenplace.net/2012/02/06/dependent-name-lookup-for-c-templates/
- https://stackoverflow.com/a/7376212/1797612
- List of C++ name resolution (and overloading) rules