Topic: can a class in an unnamed namespace be a friend?


Author: dsp@bdal.de (Daniel Spangenberg)
Date: Fri, 12 Sep 2003 23:02:13 +0000 (UTC)
Raw View
Hello, Gianluca Silvestri !

Gianluca Silvestri schrieb:

> "David Abrahams" <dave@boost-consulting.com> ha scritto nel messaggio
> news:u65k2j7qw.fsf@boost-consulting.com...
> >
> > Anyone know a way to do this?
>
> Not possible with anonymous namespaces.
> I'll rewrite your code in a clearer way:
>
> namespace   NS_this_is_a_unique_name_known_only_by_the_compiler
> {
>     class M;    //fwd decl
> }
> using  NS_this_is_a_unique_name_known_only_by_the_compiler;
>
> class RD
> {
>     friend class M;    //here you're befriending class
> NS_this_is_a_unique_name_known_only_by_the_compiler::M;
>     typedef int Q;
> };
>
> namespace  NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler
> {
>     class M
>     {
>         typedef RD::Q QQ;
>     };
> }
> using NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler;
>
> So you see that it is impossible that the declaration of class M can ma=
tch
> the previous forwarding.
>

Your argumentation is wrong: The current standard guarantees that the
compiler-known
identifier for each unnamed namespace per translation unit is the same, s=
ee
7.3.1.1/p. 1:

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

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

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."

So there is no "NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler=
" in
the
shown TU.

I think the reason is, that for class RD the friend declaration

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

denotes the nearest sourrounding namespace of RD (which seems to be the g=
lobal
one). Thus, it
cannot see M because you cannot denote it by its full-specified namespace
(which is unknown to us).

The explanation seems to be given by paragraph 3: Please have a look at t=
he
example

"Every name first declared in a namespace is a member of that namespace. =
If a
friend declaration in a
nonlocal class first declares a class or function83) the friend class or
function is a member of the innermost
enclosing namespace. The name of the friend is not found by simple name l=
ookup
until a matching declaration
is provided in that namespace scope (either before or after the class
declaration granting friendship). If
a friend function is called, its name may be found by the name lookup tha=
t
considers functions from namespaces
and classes associated with the types of the function arguments (3.4.2). =
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.[Example:
// Assume f and g have not yet been defined.
void h(int);
namespace A {
class X {
friend void f(X); // A::f is a friend
class Y {
friend void g(); // A::g is a friend
friend void h(int); // A::h is a friend
// ::h not considered
};
};
// A::f, A::g and A::h are not visible here
X x;
void g() { f(x); } // definition of A::g
void f(X) { /* ... */} // definition of A::f
void h(int) { /* ... */ } // definition of A::h
// A::f, A::g and A::h are visible here and known to be friends
}
using A::x;
void h()
{
A::f(x);
A::X::f(x); //error: f is not a member of A::X
A::X::Y::g(); // error: g is not a member of A::X::Y
}
=97end example]"

Sorry, I just had not the time to look **carefully** at it, but in the
hurry it seems the explantion for David's trouble.

Greetings,

Daniel

---
[ 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: do-not-spam-benh@bwsint.com (Ben Hutchings)
Date: Fri, 12 Sep 2003 23:02:31 +0000 (UTC)
Raw View
In article <Zy38b.47946$hE5.1687767@news1.tin.it>,
"Gianluca Silvestri" wrote:
> "David Abrahams" <dave@boost-consulting.com> ha scritto nel messaggio
> news:u65k2j7qw.fsf@boost-consulting.com...
>>
>> Anyone know a way to do this?
>
> Not possible with anonymous namespaces.
> I'll rewrite your code in a clearer way:
>
> namespace   NS_this_is_a_unique_name_known_only_by_the_compiler
> {
>     class M;    //fwd decl
> }
> using  NS_this_is_a_unique_name_known_only_by_the_compiler;
>
> class RD
> {
>     friend class M;    //here you're befriending class
> NS_this_is_a_unique_name_known_only_by_the_compiler::M;
>     typedef int Q;
> };
>
> namespace  NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler
> {
>     class M
>     {
>         typedef RD::Q QQ;
>     };
> }
> using NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler;
>
> So you see that it is impossible that the declaration of class M
> can match the previous forwarding.

I think you are wrong.  The standard says (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."

(my emphasis).  So David's code should be fine *if* the anonymous
namespace definitions only appear in one translation unit.
However, I suspect he's looking for a way to put the class
definition in a header file.

My answer: use names along the lines of your header guards.

---
[ 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: dave@boost-consulting.com (David Abrahams)
Date: Thu, 11 Sep 2003 16:33:25 +0000 (UTC)
Raw View
Anyone know a way to do this?

------- doesn't work -------

namespace
{
   class M;
}

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

namespace {
   class M { typedef RD::Q QQ; };
}

------- doesn't work -------

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

---
[ 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: dishsi@tin.it ("Gianluca Silvestri")
Date: Fri, 12 Sep 2003 09:12:24 +0000 (UTC)
Raw View
"David Abrahams" <dave@boost-consulting.com> ha scritto nel messaggio
news:u65k2j7qw.fsf@boost-consulting.com...
>
> Anyone know a way to do this?

Not possible with anonymous namespaces.
I'll rewrite your code in a clearer way:

namespace   NS_this_is_a_unique_name_known_only_by_the_compiler
{
    class M;    //fwd decl
}
using  NS_this_is_a_unique_name_known_only_by_the_compiler;

class RD
{
    friend class M;    //here you're befriending class
NS_this_is_a_unique_name_known_only_by_the_compiler::M;
    typedef int Q;
};

namespace  NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler
{
    class M
    {
        typedef RD::Q QQ;
    };
}
using NS_this_is_ANOTHER_unique_name_known_only_by_the_compiler;

So you see that it is impossible that the declaration of class M can match
the previous forwarding.

HTH
Gianluca
>
> ------- doesn't work -------
>
> namespace
> {
>    class M;
> }
>
> class RD
> {
>    friend class M;
>    typedef int Q;
> };
>
> namespace {
>    class M { typedef RD::Q QQ; };
> }
>
> ------- doesn't work -------
>
> --
> Dave Abrahams
> Boost Consulting
> www.boost-consulting.com
>
> ---
> [ 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                       ]
>

---
[ 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: Helge.Kruse-nospam@gmx.net ("Helge Kruse")
Date: Fri, 12 Sep 2003 09:12:54 +0000 (UTC)
Raw View
Your sample does work with eVC++ 3.0.

A slight modification could be the typedef. But this is unrelated to your
question:

namespace
{
   class M;
}

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

namespace
{
   class M
   {
    // use scope to get RD from global namespace.
    typedef ::RD::Q QQ;
   public:
    QQ GetNumber()
    {
     return 1;
    }
   };
}

But the class M in the unnamed namespace clashes with a class M in the
global namespace.

Helge


"David Abrahams" <dave@boost-consulting.com> schrieb im Newsbeitrag
news:u65k2j7qw.fsf@boost-consulting.com...
>
> Anyone know a way to do this?
>
> ------- doesn't work -------
>
> namespace
> {
>    class M;
> }
>
> class RD
> {
>    friend class M;
>    typedef int Q;
> };
>
> namespace {
>    class M { typedef RD::Q QQ; };
> }
>
> ------- doesn't work -------
>
> --
> Dave Abrahams
> Boost Consulting
> www.boost-consulting.com
>
> ---
> [ 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                       ]
>


---
[ 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: Fri, 12 Sep 2003 09:13:51 +0000 (UTC)
Raw View
dave@boost-consulting.com (David Abrahams) wrote

> Anyone know a way to do this?
>
> ------- doesn't work -------
>
> namespace
> {
>    class M;
> }
>
> class RD
> {
>    friend class M;
>    typedef int Q;
> };
>
> namespace {
>    class M { typedef RD::Q QQ; };
> }
>
> ------- doesn't work -------

Hmmmm....  Interesting.

One work around that should work is to nest another namespace within
the unnamed namespace and declare class M in it:

   namespace {
   namespace foo {
      class M;
   }
   }

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

   namespace {
   namespace foo {
      class M { typedef RD::Q QQ; };
   }
   }

Comeau, gcc and Borland all accept this.

---
[ 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                       ]