Topic: Is this a Bug in Comeau? (aka befriending classes in anonymous namespaces)


Author: johnchx2@yahoo.com (johnchx)
Date: Thu, 2 Oct 2003 22:14:43 +0000 (UTC)
Raw View
fvali@kumc.edu ("Faisal Vali") wrote

> The following did not work either (trying to use Qualified Name lookup
> to prevent the auto-declaration 'feature' of friend declarations)

This seems to be a common confusion.  There is no "auto-declaration
'feature'" and you can't disable it.  A friend declaration *is* a
declaration, always and everywhere.  Put another way, the name
declared as a friend is never "looked up," it is simply declared.

So the problem with this code ...

  namespace { class M; }

  class RD { friend class M; typedef int Q; };

  namespace { class M { RD::Q i; }; }

is that the friend declaration introduces a new class named M, and
there's no way rewrite the friend declaration to explicitly refer to
<unnamed>::M because <unnamed> is...well...unnamed.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: velco@fadata.bg (Momchil Velikov)
Date: Sat, 4 Oct 2003 09:05:45 +0000 (UTC)
Raw View
johnchx2@yahoo.com (johnchx) wrote in message news:<4fb4137d.0310010935.542ed05a@posting.google.com>...
> fvali@kumc.edu ("Faisal Vali") wrote
>
> > The following did not work either (trying to use Qualified Name lookup
> > to prevent the auto-declaration 'feature' of friend declarations)
>
> This seems to be a common confusion.  There is no "auto-declaration
> 'feature'" and you can't disable it.  A friend declaration *is* a
> declaration, always and everywhere.  Put another way, the name
> declared as a friend is never "looked up," it is simply declared.
>
> So the problem with this code ...
>
>   namespace { class M; }
>
>   class RD { friend class M; typedef int Q; };
>
>   namespace { class M { RD::Q i; }; }
>
> is that the friend declaration introduces a new class named M, and
> there's no way rewrite the friend declaration to explicitly refer to
> <unnamed>::M because <unnamed> is...well...unnamed.

Doesn't make sense.  A "friend" declaration is a friend declaration,
not class declaration. It does not introduce a new class, it refers
to a class specified by 1ISO/IEC 14882:1998(E) 11.4 "Friends"

   "7   A name nominated by a friend declaration shall be accessible in
        the scope of the class containing the friend declaration."

Thus in the above example "friend class M", refers to a class accessible at
namespace scope, and according to the definition of unnamed namespaces this
class is <unnamed>::M.

~velco

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: johnchx2@yahoo.com (johnchx)
Date: Sun, 5 Oct 2003 18:54:50 +0000 (UTC)
Raw View
velco@fadata.bg (Momchil Velikov) wrote
> johnchx2@yahoo.com (johnchx) wrote

> > So the problem with this code ...
> >
> >   namespace { class M; }
> >
> >   class RD { friend class M; typedef int Q; };
> >
> >   namespace { class M { RD::Q i; }; }
> >
> > is that the friend declaration introduces a new class named M, and
> > there's no way rewrite the friend declaration to explicitly refer to
> > <unnamed>::M because <unnamed> is...well...unnamed.
>
> Doesn't make sense.  A "friend" declaration is a friend declaration,
> not class declaration.  It does not introduce a new class, it refers
> to a class

Yep, that's the confusion I'm talking about.  ;-)

The statement

  friend class C;

does indeed declare a class.  Let's see if we can prove that from the
standard.

According to the grammar, the statement above is indeed a declaration,
in particular a simple-declaration, composed of a decl-spec-seq
containing the the specifier "friend" and the
elaborated-type-specifier "class C".  7.1.5.3/2 tells us that the
identifier C is looked up and "If name lookup does not find a
declaration for the name, the elatorated-type-specifier is ill-formed
unless it is of the simple form class-key identifier [ which it is, in
our example ] in which case the identifier is declared as described in
3.3.1."

So it seems clear that a friend declaration *can* declare a previously
undeclared class.  Whether it *does* depends on whether name lookup
finds an existing declaration for the identifier.  Here things become
more murky.

7.3.1.2/3 says, in part:

  When looking for a prior declaration of a class or a function
  declared as a friend, scopes outside the innermost enclosing
  namespace scope are not considered.

Let's apply this to the original example which started this
thread, but using a named namespace instead of the unnamed
namespace -- just to clarify what's going on a little.

7.3.1.1/1 tells us that "An unnamed-namespace-definition behaves
as if it were replaced by

  namespace unique { /* empty body */ }
  using namespace unique;
  namepace unique { namespace-body } "

So we can re-write the original example thus:

  namespace X {}
  using namespace X;
  namespace X { class M; }
  class RD { friend class M; typedef int Q; };
  namespace X { class M { RD::Q i; }; }

The big question is this:  when the compiler looks up the idenfifier M
in the friend delcaration, will it find X::M?

If this were ordinary name lookup, there's no question -- the
using-directive guarantees that "the names appear as if they were
declared in the nearest enclosing namespace" (7.3.4/1), i.e. the
global namespace in this example.

However, the standard also makes it clear that this appearance is an
illusion:  "A using-directive does not add any members to the
declarative region in which it appears." (ibid).  In other words,
although name lookup might find the declaration of X::M, X::M has not
become a member of the global namespace.

So, what is supposed to happen?  It's not entirely clear, and I can
see reasonable arguments on both sides.  But since class X::M isn't
actually declared in the global namespace (only visible there as if it
were), I'm inclined to the view that X::M is not considered and that
the friend declaration declares a new class M in the global namespace.

Clarification in the standard is eagerly awaited.  :-)

> specified by 1ISO/IEC 14882:1998(E) 11.4 "Friends"
>
>    "7   A name nominated by a friend declaration shall be accessible in
>         the scope of the class containing the friend declaration."
>

Accessibility is a different issue (and remember that access control
is applied only after names are resolved).  This simply means that
class B cannot declare an inaccessible (e.g. private) member of class
A to be its friend (unless B is already a friend of A).

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]