Topic: Befriending a class in anonymous namespace


Author: "Greg Herlihy" <greghe@pacbell.net>
Date: 8 May 2006 16:50:35 GMT
Raw View
James Kanze wrote:
> A very simple question: is the following translation unit legal:
>
>      namespace {
>
>      class A { public: void f() ; } ;
>      }
>      class B { friend class A ; void g() ; } ;
>
>      namespace {
>      void
>      A::f()
>      {
>          B b ;
>          b.g() ;
>      }
>      }
>
> G++ (4.0.1) says no.  I intuitively think it should be (and that
> this is a g++ bug), but I don't even know where to begin looking
> in the standard to find an real answer.
>
> FWIW: in the actual program where the problem occurs, class B is
> declared (but not defined) in a header, in order to make it a
> friend of a third class, and so cannot be in anonymous
> namespace.  Whereas all of the other classes involved are very
> much implementation details, and do belong in anonymous
> namespace.  (And the obvious work-around is to replace the
> anonymous namespace with MyPrivateNamespace, and make the friend
> declaration "friend class MyPrivateNamespace::A".)

Would you also expect this program to compile:

    namespace unique {}

    using namespace unique;

    namespace unique
    {
        class A
        {
        public:
            void f();
        };
    }

    class B
    {
        friend class A;

        void g();
    };

    namespace unique
    {
        void A::f()
        {
            B b;
            b.g();
        }
    }

It's the same program according to the definition of unnamed
namespaces. But the second program should also make clear what the
problem is in the first. In the second program, the declaration:


    friend class A;


has to be changed to


    friend class unique::A;


in order for A to be properly specified as B's friend (because the
rules governing where to look for A, state that the class declaration
for A must be found in the enclosing namespace). And yet there is no
way for B in the first program to specify A's type in the unnamed
namespace, so B cannot declare A a friend in that case.

So the first program will not compile - which is just as well - because
there can be any number of A classes declared within unnamed namespaces
in a single program. And if those types were considered as possible
friends, then a single friend declaration in one class in one header
file could inadvertently make any number of other classes that included
it, its friends - without ever knowing that those classes existed in
the first place.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kanze.james@neuf.fr (James Kanze)
Date: Mon, 8 May 2006 22:20:31 GMT
Raw View
Lucas Galfaso wrote:

 > I think you made a small mistake with your example as it should be
 >   namespace {

 >      class A { public: void f() ; } ;
 >      }
 >      class B { friend class A ; public: void g() ; } ;  /* Note the
 > extra public: */

The function is intentionally private.  It can only be accessed
in B.  And in friends of B, like A.

 >      namespace {
 >      void
 >      A::f()
 >      {
 >          B b ;
 >          b.g() ;
 >      }
 >      }

 > with that modification, the code is correct and should compile.

Obviously.  But that misses the point.

--=20
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 34

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kanze.james@neuf.fr (James Kanze)
Date: Mon, 8 May 2006 22:21:30 GMT
Raw View
Alberto Ganesh Barbati wrote:
 > James Kanze ha scritto:
 >> A very simple question: is the following translation unit
 >> legal:

 >>     namespace {

 >>     class A { public: void f() ; } ;
 >>     }
 >>     class B { friend class A ; void g() ; } ;

 >>     namespace {
 >>     void
 >>     A::f()
 >>     {
 >>         B b ;
 >>         b.g() ;
 >>     }
 >>     }

 >> G++ (4.0.1) says no.  I intuitively think it should be (and
 >> that this is a g++ bug), but I don't even know where to begin
 >> looking in the standard to find an real answer.

 > Comeau Online agrees with G++ with the following error message:

 > error: function "B::g" is inaccessible
 >           b.g() ;

 > (G++ produces an equivalent message)

 > This suggests that name lookup did not find {anon}::A when
 > parsing the friend declaration in class B.

That was my take.  A priori, I would expect name lookup to find
it; general name lookup should, and I'm pretty sure that there
would be no problem declaring a member variable of type A in B.
But name lookup in an elaborated type specifier works somewhat
differently, since it is also possible that the declaration
introduces a new name.

 > I am puzzled about the correct interpretation, but the
 > sentence that seems more relevant to me is 7.3.1.2/3: "When
 > looking for a prior declaration of a class or a function
 > declared as a friend, and when the name of the friend class or
 > function is neither a qualified name nor a template-id, scopes
 > outside the innermost enclosing namespace scope are not
 > considered."

I'm not sure that that is relevant here.  There are no scopes
outside the innermost enclosing namespace scope (which is the
global scope).

If I understand anonymous namespaces correctly, they are the
equivalent of declaring a namespace with an unmentionable name,
AND providing a "using namespace" directive for it.  So if this
is the correct behavior (and Comeau agreeing argues in that
direction), then it probably has something to do with the way
using namespace introduces the names into the new scope.

The relative statement is, I think, =A77.3.4/1: "During
unqualified name lookup, the names appear as if they were
declared in the nearest enclosing namespace which contains both
the using-directive and the nominated namespace."  That "during
unqualified name lookup" sounds like it really was meant to
exclude just about everything else -- including lookup in
elaborated type specifiers.  I still wonder if this was
intentional, or just an oversight -- it means that you cannot
befriend a class in an anonymous namespace.  (I suspect that the
major motivation for this phrase was to exclude finding such
names in qualified lookup -- and perhaps argument dependent
lookup.)

 > Of course, regular rules for unqualified lookup would find
 > {anon}::A but the phrase "neither a qualified name nor a
 > template-id" seems to hint that unqualified lookup is not
 > taking place in this case.

 > As I said, I'm very puzzled so I won't commit to a definitive
 > answer, but I would like to add that the following code:

 >     namespace Unique {
 >       class A { public: void f() ; } ;
 >     }
 >     using namespace Unique;

 >     class B { friend class A ; void g() ; } ;

 >     namespace Unique {
 >     void
 >     A::f()
 >     {
 >         B b ;
 >         b.g() ;
 >     }
 >     }

 > still produces the same error on both compilers.

I actually should have played around with it more.  But this
result is coherent with the idea that an anonymous namespace is
just a namespace with an unmentionable name, accompanied by a
using directive of this namespace.  The problem seems to be with
the way the using directive makes the names visible.

--=20
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 34

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kanze.james@neuf.fr (James Kanze)
Date: Mon, 8 May 2006 22:25:36 GMT
Raw View
Greg Herlihy wrote:
 > James Kanze wrote:
 >> A very simple question: is the following translation unit legal:

 >>      namespace {

 >>      class A { public: void f() ; } ;
 >>      }
 >>      class B { friend class A ; void g() ; } ;

 >>      namespace {
 >>      void
 >>      A::f()
 >>      {
 >>          B b ;
 >>          b.g() ;
 >>      }
 >>      }

 >> G++ (4.0.1) says no.  I intuitively think it should be (and
 >> that this is a g++ bug), but I don't even know where to begin
 >> looking in the standard to find an real answer.

 >> FWIW: in the actual program where the problem occurs, class B
 >> is declared (but not defined) in a header, in order to make
 >> it a friend of a third class, and so cannot be in anonymous
 >> namespace.  Whereas all of the other classes involved are
 >> very much implementation details, and do belong in anonymous
 >> namespace.  (And the obvious work-around is to replace the
 >> anonymous namespace with MyPrivateNamespace, and make the
 >> friend declaration "friend class MyPrivateNamespace::A".)

 > Would you also expect this program to compile:
 >     namespace unique {}

 >     using namespace unique;

 >     namespace unique
 >     {
 >         class A
 >         {
 >         public:
 >             void f();
 >         };
 >     }

 >     class B
 >     {
 >         friend class A;
 >         void g();
 >     };

 >     namespace unique
 >     {
 >         void A::f()
 >         {
 >             B b;
 >             b.g();
 >         }
 >     }

I would have, before the problem occured.

 > It's the same program according to the definition of unnamed
 > namespaces.

Quite.

 > But the second program should also make clear what the problem
 > is in the first. In the second program, the declaration:

 >
 >     friend class A;

 > has to be changed to

 >     friend class unique::A;

But why?  That is the question.

 > in order for A to be properly specified as B's friend (because
 > the rules governing where to look for A, state that the class
 > declaration for A must be found in the enclosing namespace).

And the namespace directive introduces the names from the
nominated namespace into the enclosing namespace.  At least in
the usual cases.

 > And yet there is no way for B in the first program to specify
 > A's type in the unnamed namespace, so B cannot declare A a
 > friend in that case.

 > So the first program will not compile - which is just as well
 > - because there can be any number of A classes declared within
 > unnamed namespaces in a single program.

Not in a single compilation unit.

Note that there is no doubt that something like:

     namespace { struct A{} ; }

     class B { A a ; } ;

results in undefined behavior if it occurs in a header (which is
included in more than one translation unit).  It is also
perfectly legal (and I use it) if it only occurs in a single
translation unit.

In my case, class B is the implementation class of a class using
the compilation firewall idiom.  It is declared (but not
defined) in a header, and defined in a single translation unit.
It can use classes defined in an anonymous namespace of that
translation unit for just about anything but as a friend.

 > And if those types were considered as possible friends, then a
 > single friend declaration in one class in one header file
 > could inadvertently make any number of other classes that
 > included it, its friends - without ever knowing that those
 > classes existed in the first place.

That's the case today with e.g. data declarations in the class.
That's why the ODR requires not only token equivalence, but name
binding equivalence.  You can write the code, but it violates
the ODR, so it is undefined behavior.

--=20
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 34

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 9 May 2006 05:11:54 GMT
Raw View
James Kanze ha scritto:
> I actually should have played around with it more.  But this
> result is coherent with the idea that an anonymous namespace is
> just a namespace with an unmentionable name, accompanied by a
> using directive of this namespace.  The problem seems to be with
> the way the using directive makes the names visible.

Well, it's not just an idea that an unnamed namespace is simply a
namespace with an unmentionable name, it's explicit in 7.3.1.1/1:

"An unnamed-namespace-definition behaves as if it were replaced by

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

where all occurrences of unique in a translation unit are replaced by
the same identifier and this identifier differs from all other
identifiers in the entire program."

To come back to OP, it really seems a problem of how to interpret
unqualified lookup rules in a friend declaration. If you make the name
qualified, everybody's happy ;) Both this examples compiles in g++:

------ begin
  namespace {
    namespace Foo {
      class A { public: void f() ; } ;
    }
  }

  class B { friend class Foo::A ; void g() ; } ;
------ end

and

------ begin
  namespace Foo {
    namespace {
      class A { public: void f() ; } ;
    }
  }

  class B { friend class Foo::A ; void g() ; } ;
------ end

At least those are possible workarounds for your original problem in
case it comes out that g++ and Comeau are wrong :D

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Tue, 9 May 2006 09:50:11 CST
Raw View
Alberto Ganesh Barbati wrote:
> James Kanze ha scritto:
> > I actually should have played around with it more.  But this
> > result is coherent with the idea that an anonymous namespace is
> > just a namespace with an unmentionable name, accompanied by a
> > using directive of this namespace.  The problem seems to be with
> > the way the using directive makes the names visible.
>
> Well, it's not just an idea that an unnamed namespace is simply a
> namespace with an unmentionable name, it's explicit in 7.3.1.1/1:
>
> "An unnamed-namespace-definition behaves as if it were replaced by
>
>   namespace unique { /* empty body */ }
>   using namespace unique;
>   namespace unique { namespace-body }
>
> where all occurrences of unique in a translation unit are replaced by
> the same identifier and this identifier differs from all other
> identifiers in the entire program."
>
> To come back to OP, it really seems a problem of how to interpret
> unqualified lookup rules in a friend declaration. If you make the name
> qualified, everybody's happy ;) Both this examples compiles in g++:
>
> ------ begin
>   namespace {
>     namespace Foo {
>       class A { public: void f() ; } ;
>     }
>   }
>
>   class B { friend class Foo::A ; void g() ; } ;
> ------ end
>
> and
>
> ------ begin
>   namespace Foo {
>     namespace {
>       class A { public: void f() ; } ;
>     }
>   }
>
>   class B { friend class Foo::A ; void g() ; } ;
> ------ end
>
> At least those are possible workarounds for your original problem in
> case it comes out that g++ and Comeau are wrong :D

The second workaround leads to a solution for the original problem:

    namespace
    {
        class A
        {
        public:
            void f();
        };
    }

    class B
    {
        friend class ::A;
        void g() {};
    };

    namespace
    {
        void A::f()
        {
            B b;
            b.g();
        }
    }

- which (to my surprise) gcc accepts.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: richard_corden@hotmail.com (Richard Corden)
Date: Tue, 9 May 2006 16:09:22 GMT
Raw View
James Kanze wrote:
> A very simple question: is the following translation unit legal:
>
>     namespace {
>
>     class A { public: void f() ; } ;
>     }
>     class B { friend class A ; void g() ; } ;
>
>     namespace {
>     void
>     A::f()
>     {
>         B b ;
>         b.g() ;
>     }
>     }
>
> G++ (4.0.1) says no.  I intuitively think it should be (and that
> this is a g++ bug), but I don't even know where to begin looking
> in the standard to find an real answer.


In the example, there is an elaborated-type-specifier:

class-key identifier ;

7.1.5.3/2 says to lookup 'A' as per 3.4.4.  3.4.4/2 then says as long as
the elaborated type specifier is not:

class-key identifier ;

Do lookup as per 3.4.1, otherwise introduce the class-name as per 3.3.1.

The elaborated-type-specifier is 'class-key identifier' and so we treat
it as a declaration which introduces the class-name as per 3.3.1.

Regards,

Richard

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Tue, 9 May 2006 23:04:34 GMT
Raw View
Richard Corden ha scritto:
>
> In the example, there is an elaborated-type-specifier:
>
> class-key identifier ;
>
> 7.1.5.3/2 says to lookup 'A' as per 3.4.4.  3.4.4/2 then says as long as
> the elaborated type specifier is not:
>
> class-key identifier ;
>
> Do lookup as per 3.4.1, otherwise introduce the class-name as per 3.3.1.
>
> The elaborated-type-specifier is 'class-key identifier' and so we treat
> it as a declaration which introduces the class-name as per 3.3.1.
>

I have read that, but I am unsure if it is relevant. It's true that we
have an elaborated-type-specifier, but a few sentences regarding friend
declarations seem to hint that they are an exception to these rules. Of
course I might be wrong.

On a totally unrelated issue, am I the only one that finds the phrase:

3.4.4/2: [...] unless the elaborated-type-specifier has the following form:
  class-key identifier ;
[...]

a bit strange? I mean, an elaborated-type-specifier is defined as:

elaborated-type-specifier:
  class-key ::opt nested-name-specifieropt identifier
  class-key ::opt nested-name-specifieropt templateopt template-id
  enum ::opt nested-name-specifieropt identifier
  typename ::opt nested-name-specifier identifier
  typename ::opt nested-name-specifier templateopt template-id

Now, how could an elaborated-type-specifier ever have form

  class-key identifier ;

if it can't contain semi-colons???

Yours puzzled,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Wed, 10 May 2006 10:12:14 CST
Raw View
Alberto Ganesh Barbati wrote:
> Richard Corden ha scritto:
> >
> > In the example, there is an elaborated-type-specifier:
> >
> > class-key identifier ;
> >
> > 7.1.5.3/2 says to lookup 'A' as per 3.4.4.  3.4.4/2 then says as long as
> > the elaborated type specifier is not:
> >
> > class-key identifier ;
> >
> > Do lookup as per 3.4.1, otherwise introduce the class-name as per 3.3.1.
> >
> > The elaborated-type-specifier is 'class-key identifier' and so we treat
> > it as a declaration which introduces the class-name as per 3.3.1.
> >
>
> I have read that, but I am unsure if it is relevant. It's true that we
> have an elaborated-type-specifier, but a few sentences regarding friend
> declarations seem to hint that they are an exception to these rules. Of
> course I might be wrong.
>
> On a totally unrelated issue, am I the only one that finds the phrase:
>
> 3.4.4/2: [...] unless the elaborated-type-specifier has the following form:
>   class-key identifier ;
> [...]
>
> a bit strange? I mean, an elaborated-type-specifier is defined as:
>
> elaborated-type-specifier:
>   class-key ::opt nested-name-specifieropt identifier
>   class-key ::opt nested-name-specifieropt templateopt template-id
>   enum ::opt nested-name-specifieropt identifier
>   typename ::opt nested-name-specifier identifier
>   typename ::opt nested-name-specifier templateopt template-id
>
> Now, how could an elaborated-type-specifier ever have form
>
>   class-key identifier ;
>
> if it can't contain semi-colons???

It can't - which is why it is often useful to compare the wording in
the Standard with the latest working draft (which is linked from the
WG's web page). The draft reads:

"...unless the elaborated-type-specifier appears in a declaration with
the following form:"

    class-key identifier ;

So it is clear that the semi-colon is part of the declaration and not
of the elaborated type specifier itself.

Also I came across this text, which may shed more light on this issue:

"If a friend declaration in a non-local class first declares a class or
function the friend class or function is a member of the innermost
enclosing namespace. The name of the friend is not found by simple name
lookup until a matching declaration is provided in that namespace scope
(either before or after the class definition granting friendship)."
   7.3.1.2/3

Note the word  "not" in "not found". Furthermore, I would interpret
"simple name lookup" as unqualified name lookup - in other words,
search for the class named by a friend declaration is not the same as
an unqualified name lookup.


Greg


---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Wed, 10 May 2006 18:24:48 GMT
Raw View
Greg Herlihy ha scritto:
>>
>> Now, how could an elaborated-type-specifier ever have form
>>
>>   class-key identifier ;
>>
>> if it can't contain semi-colons???
>=20
> It can't - which is why it is often useful to compare the wording in
> the Standard with the latest working draft (which is linked from the
> WG's web page). The draft reads:
>=20
> "...unless the elaborated-type-specifier appears in a declaration with
> the following form:"
>=20
>     class-key identifier ;
>=20
> So it is clear that the semi-colon is part of the declaration and not
> of the elaborated type specifier itself.

Thanks for the info. I didn't thought about checking the latest draft.
In fact I wasn't aware that there was a recent draft available to the
public, I got an access denied error last time I tried (it was quite
long ago).

> Also I came across this text, which may shed more light on this issue:
>=20
> "If a friend declaration in a non-local class first declares a class or
> function the friend class or function is a member of the innermost
> enclosing namespace. The name of the friend is not found by simple name
> lookup until a matching declaration is provided in that namespace scope
> (either before or after the class definition granting friendship)."
> =A77.3.1.2/3
>=20
> Note the word  "not" in "not found". Furthermore, I would interpret
> "simple name lookup" as unqualified name lookup - in other words,
> search for the class named by a friend declaration is not the same as
> an unqualified name lookup.

I have a different interpretation. What the sentence might mean,
according to me, is the following:

  struct A
  {
    friend struct B;
  };

  B* b1;        // error: B not found (note: unqualified)
  ::B* b2;      // error: B not found (note: qualified)
  struct B* b3; // ok: refers to same struct B as above

So although the friend declaration declares B as a struct in the global
namespace, the name B is not found "by simple name lookup" because
there's no "matching declaration" at namespace scope. The expression
"simple name lookup" is quite unfortunate, IMHO, and refers to both
qualified and unqualified lookup but with the exception of names in
elaborated-type-specifiers.

Just my opinion,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: richard_corden@hotmail.com (Richard Corden)
Date: Thu, 11 May 2006 01:52:51 GMT
Raw View
Alberto Ganesh Barbati wrote:
> Richard Corden ha scritto:
>
>>In the example, there is an elaborated-type-specifier:
>>
>>class-key identifier ;
>>
>>7.1.5.3/2 says to lookup 'A' as per 3.4.4.  3.4.4/2 then says as long as
>>the elaborated type specifier is not:
>>
>>class-key identifier ;
>>
>>Do lookup as per 3.4.1, otherwise introduce the class-name as per 3.3.1.
>>
>>The elaborated-type-specifier is 'class-key identifier' and so we treat
>>it as a declaration which introduces the class-name as per 3.3.1.
>>
>
>
> I have read that, but I am unsure if it is relevant. It's true that we
> have an elaborated-type-specifier, but a few sentences regarding friend
> declarations seem to hint that they are an exception to these rules. Of
> course I might be wrong.


The sentences later I don't think constitute a definition.  They are
just describing a specific example of  use.


> On a totally unrelated issue, am I the only one that finds the phrase:
>
> 3.4.4/2: [...] unless the elaborated-type-specifier has the following form:
>   class-key identifier ;
> [...]
>
> a bit strange? I mean, an elaborated-type-specifier is defined as:
>
> elaborated-type-specifier:
>   class-key ::opt nested-name-specifieropt identifier
>   class-key ::opt nested-name-specifieropt templateopt template-id
>   enum ::opt nested-name-specifieropt identifier
>   typename ::opt nested-name-specifier identifier
>   typename ::opt nested-name-specifier templateopt template-id
>
> Now, how could an elaborated-type-specifier ever have form
>
>   class-key identifier ;

I believe this is describing a specific type of
elaborated-type-specifier as written by the user in code.  ie. one where
the '::[opt]' and 'nested-name-specifier[opt]' are not used.

class A ;
vs
class ::A ;


This equally could have been specified using a new paragraph something
like:

An elaborated-type-specifier where the '::[opt]' and
'nested-name-specifier[opt]' are not specified is a
'simple-elaborated-type-specifier'.

And then from then on used simple-elaborated-type-specifier everywhere
it was needed.

Might be an idea to do this, given that this thread was started! :)

Regards,

Richard

>
> if it can't contain semi-colons???
>
> Yours puzzled,
>
> Ganesh
>
> ---
> [ 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.comeaucomputing.com/csc/faq.html                      ]
>

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: kanze.james@neuf.fr (James Kanze)
Date: Sun, 7 May 2006 17:51:50 GMT
Raw View
A very simple question: is the following translation unit legal:

     namespace {

     class A { public: void f() ; } ;
     }
     class B { friend class A ; void g() ; } ;

     namespace {
     void
     A::f()
     {
         B b ;
         b.g() ;
     }
     }

G++ (4.0.1) says no.  I intuitively think it should be (and that
this is a g++ bug), but I don't even know where to begin looking
in the standard to find an real answer.

FWIW: in the actual program where the problem occurs, class B is
declared (but not defined) in a header, in order to make it a
friend of a third class, and so cannot be in anonymous
namespace.  Whereas all of the other classes involved are very
much implementation details, and do belong in anonymous
namespace.  (And the obvious work-around is to replace the
anonymous namespace with MyPrivateNamespace, and make the friend
declaration "friend class MyPrivateNamespace::A".)

--=20
James Kanze                                    kanze.james@neuf.fr
Conseils en informatique orient=E9e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France +33 (0)1 30 23 00 34

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Lucas Galfaso" <lgalfaso@gmail.com>
Date: Mon, 8 May 2006 11:27:26 CST
Raw View
I think you made a small mistake with your example as it should be
  namespace {

     class A { public: void f() ; } ;
     }
     class B { friend class A ; public: void g() ; } ;  /* Note the
extra public: */

     namespace {
     void
     A::f()
     {
         B b ;
         b.g() ;
     }
     }

with that modification, the code is correct and should compile.

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: AlbertoBarbati@libero.it (Alberto Ganesh Barbati)
Date: Mon, 8 May 2006 16:45:33 GMT
Raw View
James Kanze ha scritto:
> A very simple question: is the following translation unit legal:
>
>     namespace {
>
>     class A { public: void f() ; } ;
>     }
>     class B { friend class A ; void g() ; } ;
>
>     namespace {
>     void
>     A::f()
>     {
>         B b ;
>         b.g() ;
>     }
>     }
>
> G++ (4.0.1) says no.  I intuitively think it should be (and that
> this is a g++ bug), but I don't even know where to begin looking
> in the standard to find an real answer.

Comeau Online agrees with G++ with the following error message:

error: function "B::g" is inaccessible
          b.g() ;

(G++ produces an equivalent message)

This suggests that name lookup did not find {anon}::A when parsing the
friend declaration in class B.

I am puzzled about the correct interpretation, but the sentence that
seems more relevant to me is 7.3.1.2/3: "When looking for a prior
declaration of a class or a function declared as a friend, and when the
name of the friend class or function is neither a qualified name nor a
template-id, scopes outside the innermost enclosing namespace scope are
not considered."

Of course, regular rules for unqualified lookup would find {anon}::A but
the phrase "neither a qualified name nor a template-id" seems to hint
that unqualified lookup is not taking place in this case.

As I said, I'm very puzzled so I won't commit to a definitive answer,
but I would like to add that the following code:

    namespace Unique {
      class A { public: void f() ; } ;
    }
    using namespace Unique;

    class B { friend class A ; void g() ; } ;

    namespace Unique {
    void
    A::f()
    {
        B b ;
        b.g() ;
    }
    }

still produces the same error on both compilers.

Just my 2 eurocent,

Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]