I've been getting a very unusual error from g++ claiming that a type alias is private. After hours of reducing my code, I've arrived at the following minimal test case:
template <typename Dummy>
class Test {
struct CatDog {
static void meow ()
{
CrazyHouse::TheCatDog::meow();
}
struct Dog {
static void bark ();
};
};
struct CrazyHouse {
using TheCatDog = CatDog;
static void startMadness ()
{
TheCatDog::meow();
TheCatDog::Dog::bark();
}
};
public:
static void init ()
{
CrazyHouse::startMadness();
}
};
int main ()
{
Test<void> t;
t.init();
}
The error with g++ 4.8.2 is:
test.cpp: In instantiation of 'static void Test<Dummy>::CatDog::meow() [with Dummy = void]':
test.cpp:19:29: required from 'static void Test<Dummy>::CrazyHouse::startMadness() [with Dummy = void]'
test.cpp:27:34: required from 'static void Test<Dummy>::init() [with Dummy = void]'
test.cpp:34:12: required from here
test.cpp:15:33: error: 'using TheCatDog = struct Test<void>::CatDog' is private
using TheCatDog = CatDog;
^
test.cpp:6:41: error: within this context
CrazyHouse::TheCatDog::meow();
^
Clang 3.4 accepts the same code. What's going on here, is this a g++ bug?
Doing any of the following stops the error from occuring:
Test
into a class, as opposed to a template class.TheCatDog::Dog::bark();
to CatDog::Dog::bark();
.CrazyHouse
class and merging its contents in Test
.CatDog
class, merging its contents into Test
and changing the TheCatDog
alias to point to Test
.Name lookup on the identifier CatDog
finds Test::CatDog
which is declared private
. The access is performed from CrazyHouse
, which is not a friend
of Test
. Therefore it's an illegal access to a protected member.
As @sj0h notes, in C++11 your example becomes valid because they decided to extend access to the bodies of nested classes in the same way as member functions.
C++98:
The members of a nested class have no special access to members of an enclosing class, nor to classes or functions that have granted friendship to an enclosing class; the usual access rules (clause 11) shall be obeyed.
C++11:
A nested class is a member and as such has the same access rights as any other member.
(Members have the right to access private
members of the enclosing class.)
However, this change does not appear to be implemented in GCC even in a recent build of version 4.9. So, to be safe, it can't hurt to add a friend
declaration. This must go after the definition of the member:
friend struct CrazyHouse;
Note that this doesn't accomplish exactly the same thing as the C++11 change, because friend
ship is not transitive whereas access granted by nested membership is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With