Compiling this code using g++ 4.2.1:
struct S { };
template<typename T> struct ST { };
template<typename BaseType>
class ref_count : private BaseType { };
template<typename RefCountType>
class rep_base : public RefCountType { };
class wrap_rep : public rep_base<ref_count<S> > {
typedef rep_base<ref_count<S> > base_type; // line 11
};
I get:
bug.cpp:1: error: ‘struct S’ is inaccessible
bug.cpp:11: error: within this context
However, if I change the wrap_rep
class to use ST
:
class wrap_rep : public rep_base<ref_count< ST<int> > > {
typedef rep_base<ref_count< ST<int> > > base_type;
};
it compiles fine. Alternatively, if I change the original code to:
class wrap_rep : public rep_base<ref_count<S> > {
typedef rep_base<ref_count< ::S > > base_type; // now using ::
};
it also compiles fine. To me, the original code seems fine as-is. Is this a g++ bug? If not, then why does using a template work? And, for the other case, why is the ::S
necessary?
Your struct
S
is a base class ofwrap_rep
which means that it's injected intowrap_rep
as if there was an anonymous typedef.Using the operator
::
beforeS
in your typedef will tell your compiler not to use theS
you inherit from, butS
in the global namespace.See this link.
Both of those codes are invalid (only the last one is valid), but your compiler (which is not conforming) only diagnoses one. As another answer says, this uses the injected class name. A class
S
is considered to have a member nameS
denoting that same class. For example (notice the "class" keyword beforeS::S
in the first example is necessary to force a reference to the injected class name, instead of the default constructor):Class templates also have an injected class name. Like the injected class name, it is inherited to derived classes, and thus
ST<int>
is ill-formed because it uses that injected class name, which however is not accessible. If you use GCC less 4.5, it may have something to do with a change introduced with GCC4.5:To have a bit more fun with injected class names - notice that the injected class name is not equivalent to a typedef as one might think first. The injected class name is a class-name, but is not classified as a typedef-name, which means it can be hidden by function, object or enumerator names:
To refer to the injected class name you can say
class S::S
(likewise, in a base-class list, non-type names are ignored thus you don't need special pre-cautions there), but a simple lookup toS::S
will refer to the data-member.The original code compiled fine in "Sun WorkShop 6 update 2 Compilers C++". This is the only one I have access to in my office. May be try on any other compiler you have.