On May 30, 1:35 pm, Eric Lilja <mindcoo...@gmail.comwrote:
Hello, consider this program:
class Outer
{
public:
class Base
{
friend class Outer;
public:
Base(int n) : n_(n) {}
protected:
int n_;
};
class Child1 : public Base
{
friend class Outer;
friend class Child2;
The standard is far from clear about this, but the most
reasonable interpretation of the current version is that
this declares (and refers to) a class at namespace scope.
At least, that would seem to be the intent: from a note
(non-normative) in §3.3.1/8 (of the latest draft): "friend
declarations refer to functions or classes that are members
of the nearest enclosing namespace,[...]". The note is,
however, contradicted in §11.4/11, where it says:For a
friend class declaration, if there is no prior declaration,
the class that is specified belongs to the innermost
enclosing non-class scope,[...]", but the first sentence of
the paragraph starts "If a friend declaration appears in a
local class[...]" and this "if" seems to be meant to apply
to the entire paragraph, and not just the first sentence.
Note that the text concerning friendship is still somewhat
in a state of flux. The next version of the standard will
differ considerably from the current one, and may differ
from the text in the latest draft as well. Also: since the
text is excedingly unclear, and in a state of flux,
compilers will vary greatly with regards to what they
actually do.
parent[(*this).header] = y; // Update root.
else if (x == left[parent[x]])
left[parent[x]] = y;
else
right[parent[x]] = y;
public:
Child1(int n) : Base(n) {}
};
class Child2 : public Base
Note that according to the above interpretation, this is
*not* the class that Child1 declared as a friend.
{
friend class Outer;
public:
Child2(int n) : Base(n) {}
Child2(const Child1& rhs) : Base(rhs.n_) {}
};
};
int main()
{
Outer::Child1 c1(4711);
Outer::Child2 c2(c1);
}
It compiles with MSVC++ 8.0 SP1 and gcc 4.2.0. It does not compile
with gcc 3.4.4:
$ g++ -Wall -Wextra -std=c++98 -pedantic -g foo.cpp -o runme.exe
foo.cpp: In constructor `Outer::Child2::Child2(const Outer::Child1&)':
foo.cpp:10: error: `int Outer::Base::n_' is protected
foo.cpp:27: error: within this context
Also, worth mentioning is that gcc 4.2.0 doesn't need quite as many
friend declarations as MSVC++ 8.0 SP1 does...
It's possible the g++ is already implementing parts of the
newer standard, which will (I think) make member classes
implicitly friends (or more precisely, a member class is a
member of the enclosing class, and thus has access to
private and protected members of that class).
Note that I've not followed this evolution very closely,
and I could be wrong with regards to many of the details.
The important point to keep in mind, I think, is that it
isn't clear, it is evolving, and that compilers will vary
enormously. About the one point that does seem clear (at
least to me) is that the compiler does do name lookup as if
the friend specifier was absent, and IF it finds the name,
that is what is being declared friend. Thus, in the above
case, you might start with:
class Outer
{
public:
class Base ;
class Child1 ;
class Child2 ;
// ...
} ;
This ensures that any later references to Outer::Base,
Outer::Child1 or Outer::Child2 will find the correct class
(and be legal---if qualified name look-up fails, I think it
is an error).
is this code valid according to the standard and is it
being rejected by the older gcc because of a bug or a
failure to follow the standard as closely as gcc 4.2.0?
I think part of the motivation for the rewrite in the
standard is that interpreted literally, the current standard
makes it impossible to declare a nested class friend. This
was never the intent, and as far as I know, was never
actually implemented by any compiler. What compilers did
implement, however, varied, and will continue to vary, at
least until the next version of the standard is released and
compilers implement it.
If you want to really know what is being planned, and how
this is evolving, I'd suggest asking the question in
comp.std.c++. Be aware, however, that this won't
necessarily help you now, with the compilers you have today.
--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34