friend and unnamed namespace

Discussion in 'C++' started by Ivan Mascovich, Mar 2, 2006.

  1. Previous posts (and compilers) confirm that

    class X
    {
    friend void Y() ;
    } ;

    does not match

    namespace
    {
    void y ()
    {
    }

    }

    Is there any way to declare the friend such that it will match a function
    in an unnamed namespace --- OR does one simply have to do things the old
    way with static?
    Ivan Mascovich, Mar 2, 2006
    #1
    1. Advertising

  2. * Ivan Mascovich:
    > Previous posts (and compilers) confirm that
    >
    > class X
    > {
    > friend void Y() ;
    > } ;
    >
    > does not match
    >
    > namespace
    > {
    > void y ()
    > {
    > }
    >
    > }


    Well, it can't, because Y and y are two different names.

    But if you use the same function name (et cetera), then yes, there's no
    way to forward-declare a function in an anonymous namespace outside of
    that namespace, because each anonymous namespace is a different
    namespace, and can't be referred to.


    > Is there any way to declare the friend such that it will match a function
    > in an unnamed namespace


    Not in any useful way, no (if you have the anonyous namespace before the
    class definition it rather defeats the purpose).


    > --- OR does one simply have to do things the old way with static?


    static is good, whether you mean a namespace scope static function, or a
    static member function; the first restricts access to this translation
    unit, and the second can restrict access to this class.


    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Mar 3, 2006
    #2
    1. Advertising

  3. Ivan Mascovich wrote:
    > Previous posts (and compilers) confirm that
    >
    > class X
    > {
    > friend void Y() ;
    > } ;
    >
    > does not match
    >
    > namespace
    > {
    > void y ()
    > {
    > }
    >
    > }


    First of all, 'Y' and 'y' are different names in C++.

    > Is there any way to declare the friend such that it will match a function
    > in an unnamed namespace --- OR does one simply have to do things the old
    > way with static?


    There is no way. Take a look:
    ------------------------------------------
    class A;
    namespace NS {
    int Y(A*);
    }

    using namespace NS;

    int y = Y(0);

    class A {
    int a;
    friend int NS::Y(A*); /////////// *****************
    };

    namespace NS {
    int Y(A* pa) {
    return pa->a;
    }
    }

    int main() {
    A a;
    Y(&a);
    }
    -----------------------------------------

    Imagine that 'NS' does not exist, but is replaced with some unique to your
    translation unit identifier. That's what essentially happens when you
    create an unnamed namespace. Now, notice that if you remove the 'NS::'
    from the 'friend' declaration in 'class A', the friend declaration will
    _introduce_ the name 'Y' into the _global_ namespace. Then the program
    will be ill-formed due to two reasons: access to 'a' member in 'Y' is not
    granted and in 'main' the call to 'Y' is ambiguous.

    That's the problem with 'friend' declarations, not with unnamed namespaces
    and the way to combat it would be either name your namespace and use the
    name in the 'friend' as well, or (temporarily, until your compiler stops
    supporting those) use 'static'. The use of 'static' for declaring any
    functions you don't want other modules to see has been deprecated.

    V
    --
    Please remove capital As from my address when replying by mail
    Victor Bazarov, Mar 3, 2006
    #3
  4. Alf P. Steinbach wrote:
    > * Ivan Mascovich:
    >
    >> Previous posts (and compilers) confirm that
    >>
    >> class X
    >> {
    >> friend void Y() ;
    >> } ;
    >>
    >> does not match
    >>
    >> namespace
    >> {
    >> void y ()
    >> {
    >> }
    >>
    >> }

    >
    >
    > Well, it can't, because Y and y are two different names.
    >
    > But if you use the same function name (et cetera), then yes, there's no
    > way to forward-declare a function in an anonymous namespace outside of
    > that namespace, because each anonymous namespace is a different
    > namespace, and can't be referred to.


    That's not true. You can forward-declare any function in an unnamed
    namespace in the _same_ translation unit. The problem is that forward-
    declaring it does not help.

    >> Is there any way to declare the friend such that it will match a
    >> function in an unnamed namespace

    >
    >
    > Not in any useful way, no (if you have the anonyous namespace before the
    > class definition it rather defeats the purpose).


    No. The problem in the way 'friend' works, not in the way unnamed
    namespaces work.

    > > --- OR does one simply have to do things the old way with static?

    >
    > static is good, whether you mean a namespace scope static function, or a
    > static member function; the first restricts access to this translation
    > unit, and the second can restrict access to this class.


    A static member of the same class has all access it needs, there is no
    need to declare it a friend.

    V
    --
    Please remove capital As from my address when replying by mail
    Victor Bazarov, Mar 3, 2006
    #4
  5. * Victor Bazarov:
    > Alf P. Steinbach wrote:
    >> * Ivan Mascovich:
    >>
    >>> Previous posts (and compilers) confirm that
    >>>
    >>> class X
    >>> {
    >>> friend void Y() ;
    >>> } ;
    >>>
    >>> does not match
    >>>
    >>> namespace
    >>> {
    >>> void y ()
    >>> {
    >>> }
    >>>
    >>> }

    >>
    >>
    >> Well, it can't, because Y and y are two different names.
    >>
    >> But if you use the same function name (et cetera), then yes, there's
    >> no way to forward-declare a function in an anonymous namespace outside
    >> of that namespace, because each anonymous namespace is a different
    >> namespace, and can't be referred to.

    >
    > That's not true. You can forward-declare any function in an unnamed
    > namespace in the _same_ translation unit.


    In practice, with current compilers, that seems to be the case, yes.

    However, the standard seems quite clear when it /syntactically/ reserves
    the mechanism of namespace extension to named namespaces

    And requires every anonymous namespace (not making any distiction
    between "in the same translation unit" or otherwise) to behave as if it
    had a globally unique name.

    Which would make it different to declare a function in one anonymous
    namespace and define it in another, even in the same translation unit.

    Perhaps you could cite the relevant part of the standard that allows an
    anonymous namespace to be extended (in the same translation unit)?


    > The problem is that forward- declaring it does not help.
    >
    >>> Is there any way to declare the friend such that it will match a
    >>> function in an unnamed namespace

    >>
    >>
    >> Not in any useful way, no (if you have the anonyous namespace before
    >> the class definition it rather defeats the purpose).

    >
    > No. The problem in the way 'friend' works, not in the way unnamed
    > namespaces work.


    Again, that seems to be the case in practice, with current compilers.

    However, again I'm afraid I must ask for language in the standard that
    supports that view.

    It may be that I'm blind on both eyes, but it may be that we're on the
    trail of not just one but two different defects in the standard.


    >> > --- OR does one simply have to do things the old way with static?

    >>
    >> static is good, whether you mean a namespace scope static function, or
    >> a static member function; the first restricts access to this
    >> translation unit, and the second can restrict access to this class.

    >
    > A static member of the same class has all access it needs, there is no
    > need to declare it a friend.


    That's right, that's why the OP mentioned it as an alternative.

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Mar 3, 2006
    #5
  6. Alf P. Steinbach wrote:
    > [..]
    > Perhaps you could cite the relevant part of the standard that allows
    > an anonymous namespace to be extended (in the same translation unit)?
    >


    I am not going to cite it. Open it on page 115 and read 7.3.1.1.
    Pay special attention to the words "where _all_ occurrences..."
    (emphasis mine).

    > [..]


    V
    --
    Please remove capital As from my address when replying by mail
    Victor Bazarov, Mar 3, 2006
    #6
  7. Ivan Mascovich

    Pete Becker Guest

    Alf P. Steinbach wrote:
    >
    > However, the standard seems quite clear when it /syntactically/ reserves
    > the mechanism of namespace extension to named namespaces


    Well, "reserves" is a bit strong. Yes, there are two grammar
    productions, one for an unnamed-namespace-definition, and one for an
    unnamed-namespace-extension. The obvious purpose of that distinction is
    to be able to say that the name of an unnamed-namespace-extension must
    have been the name in a prior unnamed-namespace-definition. I'd be leary
    of reading more subtle implications into that.

    >
    > And requires every anonymous namespace (not making any distiction
    > between "in the same translation unit" or otherwise) to behave as if it
    > had a globally unique name.


    On the contrary: 7.3.1/1 says

    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. [emphasis added]

    Now, certainly, the following is valid:

    namespace x { /* empty body */ } // definition
    using namespace x;
    namespace x { int i; } // extension

    namespace x { /* empty body */ } // extension
    using namespace x;
    namespace x { int j; } // extension

    and if you replace 'x' by 'unique' that's what you get from

    namespace { int i; }
    namespace { int j; }

    --

    Pete Becker
    Roundhouse Consulting, Ltd.
    Pete Becker, Mar 3, 2006
    #7
  8. * Victor Bazarov:
    > Alf P. Steinbach wrote:
    >> [..]
    >> Perhaps you could cite the relevant part of the standard that allows
    >> an anonymous namespace to be extended (in the same translation unit)?
    >>

    >
    > I am not going to cite it. Open it on page 115 and read 7.3.1.1.
    > Pay special attention to the words "where _all_ occurrences..."
    > (emphasis mine).


    Yep, you're right about that.

    That leaves the second part I addressed in that posting, your statement

    "Now, notice that if you remove the 'NS::' from the 'friend'
    declaration in 'class A', the friend declaration will _introduce_ the
    name 'Y' into the _global_ namespace."

    Yes, that's how current compilers behave, but finding that in the
    standard is beyond me.

    §3.3/4 says a friend declaration "may introduce a (possibly not visible)
    name into an enclosing namespace".

    §3.3.1/6 contrariwise says friend declarations "do not introduce new
    names into [the nearest enclosing namespace]".

    §7.3.1.2/3 is perhaps the one nearest to saying what you say (and
    current compilers do), namely that

    "If a friend declaration in a non-local class first declares a class
    or function[note 83] the friend class or function is a member of the
    innermost enclosing namespace."

    where note 83 is "this implies that the name of the class or function is
    unqualified".

    A using-declaration is a declaration, so

    using SomeNameSpace::foo;

    should suffice as a pre-declaration of foo() in the namespace enclosing
    the class -- but it does not, with current compilers.

    §11.4/7, in the "Friends" section, requires that

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

    And there is no other requirement, as far as I can see.

    Is there perhaps something I have overlooked?

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Mar 3, 2006
    #8
  9. * Pete Becker:
    > 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. [emphasis added]


    Yep, thanks!

    I may have to invest in new glasses... ;-)

    Perhaps there's something I likewise simply don't see (before it's
    pointed out) regarding the effect of unqualified names in friend
    function declarations; I'm aware of §7.3.1.2/3, but what I'm able to see
    of it -- heh -- doesn't seem to preclude something like

    namespace ANameSpace{ void x(); }
    using ANameSpace::x; // If this isn't 'first declared', then
    // a 'void x() {}' here should compile?

    class Foo
    {
    friend void x();
    };

    with the definition of ANameSpace::x then having friendship status (yes,
    I know that's not how current compilers work).

    What I do see is that §11.4/7 requires that

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

    and 'void x()' is accessible, isn't it?

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Mar 3, 2006
    #9
  10. Alf P. Steinbach wrote:
    > [..]
    > "Now, notice that if you remove the 'NS::' from the 'friend'
    > declaration in 'class A', the friend declaration will _introduce_ the
    > name 'Y' into the _global_ namespace."
    >
    > Yes, that's how current compilers behave, but finding that in the
    > standard is beyond me.
    >
    > §3.3/4 says a friend declaration "may introduce a (possibly not visible)
    > name into an enclosing namespace".
    >
    > §3.3.1/6 contrariwise says friend declarations "do not introduce new
    > names into [the nearest enclosing namespace]".


    That's in a "Note", which is non-normative.

    > §7.3.1.2/3 is perhaps the one nearest to saying what you say (and
    > current compilers do), namely that
    >
    > "If a friend declaration in a non-local class first declares a class
    > or function[note 83] the friend class or function is a member of the
    > innermost enclosing namespace."
    >
    > where note 83 is "this implies that the name of the class or function is
    > unqualified".
    >
    > A using-declaration is a declaration, so
    >
    > using SomeNameSpace::foo;
    >
    > should suffice as a pre-declaration of foo() in the namespace enclosing
    > the class -- but it does not, with current compilers.


    'using' declaration like that does not make 'foo' a _member_ [of the
    global, I presume, namespace], it just makes it _resolvable_.

    > §11.4/7, in the "Friends" section, requires that
    >
    > "A name nominated by a friend declaration shall be accessible in the
    > scope of the class containing the friend declaration"
    >
    > And there is no other requirement, as far as I can see.
    >
    > Is there perhaps something I have overlooked?


    Maybe. AFA I'm concerned, this is one of the most convoluted and unclear
    parts of the language, which suggests that declaring anything as 'friend'
    should be generally avoided.

    V
    --
    Please remove capital As from my address when replying by mail
    Victor Bazarov, Mar 3, 2006
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Razmig K
    Replies:
    3
    Views:
    668
    John L Fjellstad
    Sep 5, 2003
  2. marco_segurini
    Replies:
    4
    Views:
    997
    Rob Williscroft
    Jun 16, 2004
  3. marco_segurini

    unnamed namespace and friend

    marco_segurini, Feb 3, 2005, in forum: C++
    Replies:
    1
    Views:
    347
    msalters
    Feb 3, 2005
  4. John Ratliff

    unnamed namespace and friend method

    John Ratliff, Feb 6, 2008, in forum: C++
    Replies:
    9
    Views:
    2,435
    Alf P. Steinbach
    Feb 8, 2008
  5. Johannes Schaub (litb)

    Experiment with unnamed namespace and template

    Johannes Schaub (litb), Oct 13, 2010, in forum: C++
    Replies:
    4
    Views:
    489
    Victor Bazarov
    Oct 13, 2010
Loading...

Share This Page