About friend declaration

Discussion in 'C++' started by WaterWalk, May 24, 2008.

  1. WaterWalk

    WaterWalk Guest

    I find friend declaration just very tricky. I tried the following
    examples on both MingW(gcc 3.4.2) and VC++ 2005. The results are
    surprising.

    Example1:
    namespace ns1
    {
    class Test
    {
    friend void func()
    {
    printf("func in %s\n", __FILE__);
    }
    };
    }

    int main()
    {
    ns1::func();
    }

    ---End Example1---
    gcc: compiles and works
    VC++: compile error: 'func': candidate function(s) not accessible

    Example2:
    -file1.cpp
    namespace ns1
    {
    class Test
    {
    friend void func();
    };
    }

    int main()
    {
    ns1::func2("abc");
    }

    -file2.cpp
    namespace ns1
    {
    void func()
    {
    printf("func in %s\n", __FILE__);
    }
    }
    ---end Example2---
    gcc: compiles and works
    VC++: compiles and works

    I'm rather confused. Does a friend function declaration make it as if
    it's also declared in the enclosing namespace? At least in example2,
    it seems to be so.

    What about Example1? What is the right behavior?
    WaterWalk, May 24, 2008
    #1
    1. Advertising

  2. WaterWalk wrote:

    > I find friend declaration just very tricky. I tried the following
    > examples on both MingW(gcc 3.4.2) and VC++ 2005. The results are
    > surprising.
    >
    > Example1:
    > namespace ns1
    > {
    > class Test
    > {
    > friend void func()
    > {
    > printf("func in %s\n", __FILE__);
    > }
    > };
    > }
    >
    > int main()
    > {
    > ns1::func();
    > }
    >
    > ---End Example1---
    > gcc: compiles and works


    It does not on GCC 4.1.2.

    error: 'func' is not a member of 'ns1'

    > VC++: compile error: 'func': candidate function(s) not accessible
    >
    > Example2:
    > -file1.cpp
    > namespace ns1
    > {
    > class Test
    > {
    > friend void func();
    > };
    > }
    >
    > int main()
    > {
    > ns1::func2("abc");
    > }


    How does "func2" enter the picture here? This cannot compile as it is,
    so you obviously did not post the actual code.


    --
    Christian Hackl
    Christian Hackl, May 24, 2008
    #2
    1. Advertising

  3. WaterWalk

    James Kanze Guest

    On May 24, 3:44 pm, WaterWalk <> wrote:
    > I find friend declaration just very tricky. I tried the
    > following examples on both MingW(gcc 3.4.2) and VC++ 2005. The
    > results are surprising.


    > Example1:
    > namespace ns1
    > {
    > class Test
    > {
    > friend void func()
    > {
    > printf("func in %s\n", __FILE__);
    > }


    Note that although the function you define is ns1::func, the
    declaration for this function is only visible in Test. Since
    the function has no parameters, ADL won't enter into effect
    either.

    > };
    > }


    > int main()
    > {
    > ns1::func();


    The name shouldn't be visible here.

    > }


    > ---End Example1---
    > gcc: compiles and works


    Not with the version I have.

    > VC++: compile error: 'func': candidate function(s) not accessible


    "not visible" would be a better message. Or simply that it
    cannot find the function.

    Earlier (pre-standard) versions of C++ injected the name of a
    friend into the surrounding scope, so some compilers may still
    do this for reasons of backwards compatibility.

    > Example2:
    > -file1.cpp
    > namespace ns1
    > {
    > class Test
    > {
    > friend void func();
    > };
    >
    > }


    > int main()
    > {
    > ns1::func2("abc");


    I presume you mean ns1::func.

    > }


    > -file2.cpp
    > namespace ns1
    > {
    > void func()
    > {
    > printf("func in %s\n", __FILE__);
    > }
    > }


    > ---end Example2---
    > gcc: compiles and works
    > VC++: compiles and works


    This should have the same problem as the above. There is no
    declaration of ns1::func visible when you compile main, so the
    code shouldn't compile. (Again, the g++ I have here doesn't
    compile it. The error message is:
    names.cc:20: error: ‘func’ is not a member of ‘ns1’
    Not perfect, either: `func' cannot be found in `ns1' would be
    better.)

    > I'm rather confused. Does a friend function declaration make
    > it as if it's also declared in the enclosing namespace?


    No, but it did in pre-standard C++. (More correctly, it
    injected the name into file scope---there weren't namespaces ini
    pre-standard C++, so there was no namespace scope.)

    I forget the reason why the committee changed this. (I've been
    told at least a half dozen times. Each time, I recognize that
    it is valid, but end up forgetting exactly what it was.) There
    was discussion concerning the possibility of breaking existing
    code, but in practice, no one could figure out a possible use
    for a friend function that didn't have an argument which
    depended on the class it was a friend of, and with such an
    argument, ADL finds the function, even if the declaration isn't
    visible.

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, May 24, 2008
    #3
  4. WaterWalk

    WaterWalk Guest

    On May 25, 1:26 am, James Kanze <> wrote:
    > On May 24, 3:44 pm, WaterWalk <> wrote:
    >
    > > I find friend declaration just very tricky. I tried the
    > > following examples on both MingW(gcc 3.4.2) and VC++ 2005. The
    > > results are surprising.
    > > Example1:
    > > namespace ns1
    > > {
    > > class Test
    > > {
    > > friend void func()
    > > {
    > > printf("func in %s\n", __FILE__);
    > > }

    >
    > Note that although the function you define is ns1::func, the
    > declaration for this function is only visible in Test. Since
    > the function has no parameters, ADL won't enter into effect
    > either.
    >
    > > };
    > > }
    > > int main()
    > > {
    > > ns1::func();

    >
    > The name shouldn't be visible here.
    >
    > > }
    > > ---End Example1---
    > > gcc: compiles and works

    >
    > Not with the version I have.
    >
    > > VC++: compile error: 'func': candidate function(s) not accessible

    >
    > "not visible" would be a better message. Or simply that it
    > cannot find the function.
    >
    > Earlier (pre-standard) versions of C++ injected the name of a
    > friend into the surrounding scope, so some compilers may still
    > do this for reasons of backwards compatibility.
    >
    > > Example2:
    > > -file1.cpp
    > > namespace ns1
    > > {
    > > class Test
    > > {
    > > friend void func();
    > > };

    >
    > > }
    > > int main()
    > > {
    > > ns1::func2("abc");

    >
    > I presume you mean ns1::func.
    >
    > > }
    > > -file2.cpp
    > > namespace ns1
    > > {
    > > void func()
    > > {
    > > printf("func in %s\n", __FILE__);
    > > }
    > > }
    > > ---end Example2---
    > > gcc: compiles and works
    > > VC++: compiles and works

    >
    > This should have the same problem as the above. There is no
    > declaration of ns1::func visible when you compile main, so the
    > code shouldn't compile. (Again, the g++ I have here doesn't
    > compile it. The error message is:
    > names.cc:20: error: ‘func’ is not a member of ‘ns1’
    > Not perfect, either: `func' cannot be found in `ns1' would be
    > better.)
    >
    > > I'm rather confused. Does a friend function declaration make
    > > it as if it's also declared in the enclosing namespace?

    >
    > No, but it did in pre-standard C++. (More correctly, it
    > injected the name into file scope---there weren't namespaces ini
    > pre-standard C++, so there was no namespace scope.)
    >
    > I forget the reason why the committee changed this. (I've been
    > told at least a half dozen times. Each time, I recognize that
    > it is valid, but end up forgetting exactly what it was.) There
    > was discussion concerning the possibility of breaking existing
    > code, but in practice, no one could figure out a possible use
    > for a friend function that didn't have an argument which
    > depended on the class it was a friend of, and with such an
    > argument, ADL finds the function, even if the declaration isn't
    > visible.
    >


    Thanks for this information. But at the same time, I find some curious
    statements in the c++ standard and some books:
    c++ standard 3.3/4
    In particular, elaborated-type-specifiers
    (3.3.1) and friend declarations (11.4) may introduce a (possibly not
    visible) name into an enclosing namespace;
    these restrictions apply to that region.

    c++ standard 3.3.1/6
    [Note: friend declarations refer to functions or classes that are
    members of the nearest enclosing namespace,
    but they do not introduce new names into that namespace (7.3.1.2).

    To me, they look to say the opposite things. What's more:
    C++ Primer, 4th edition, in Chapter 12.5
    A friend declaration introduces the named class or nonmember function
    into the surrounding scope.

    In the same chapter, an example is given:
    class X
    {
    friend class Y;
    friend void f();
    };

    class Z
    {
    Y *ymem; //ok, declaration for class Y introduced by friend in X
    void g() {return ::f();} //ok, declaration of f introduced by X
    };

    Another source of confusion is how a friend declaration affects name
    lookup in the class granting friendship? For example:
    class X
    {
    public:
    void show();
    Y *py; // is Y visible ?
    friend claxx Y
    friend void f();
    };

    void X::show()
    {
    f(); //is f visible?
    }
    In X's member function definitions, will f be visible? In X's member
    declarations, will Y be visible?

    I searched in the standard, but didn't find clues in it's chapters
    about name lookup(in 3.4).
    WaterWalk, May 25, 2008
    #4
  5. WaterWalk

    WaterWalk Guest

    On May 25, 2:32 pm, "Alf P. Steinbach" <> wrote:
    > * WaterWalk:
    >
    >
    >
    > > On May 25, 1:26 am, James Kanze <> wrote:
    > >> On May 24, 3:44 pm, WaterWalk <> wrote:

    >
    > >>> I find friend declaration just very tricky. I tried the
    > >>> following examples on both MingW(gcc 3.4.2) and VC++ 2005. The
    > >>> results are surprising.
    > >>> Example1:
    > >>> namespace ns1
    > >>> {
    > >>> class Test
    > >>> {
    > >>> friend void func()
    > >>> {
    > >>> printf("func in %s\n", __FILE__);
    > >>> }
    > >> Note that although the function you define is ns1::func, the
    > >> declaration for this function is only visible in Test. Since
    > >> the function has no parameters, ADL won't enter into effect
    > >> either.

    >
    > >>> };
    > >>> }
    > >>> int main()
    > >>> {
    > >>> ns1::func();
    > >> The name shouldn't be visible here.

    >
    > >>> }
    > >>> ---End Example1---
    > >>> gcc: compiles and works
    > >> Not with the version I have.

    >
    > >>> VC++: compile error: 'func': candidate function(s) not accessible
    > >> "not visible" would be a better message. Or simply that it
    > >> cannot find the function.

    >
    > >> Earlier (pre-standard) versions of C++ injected the name of a
    > >> friend into the surrounding scope, so some compilers may still
    > >> do this for reasons of backwards compatibility.

    >
    > >>> Example2:
    > >>> -file1.cpp
    > >>> namespace ns1
    > >>> {
    > >>> class Test
    > >>> {
    > >>> friend void func();
    > >>> };
    > >>> }
    > >>> int main()
    > >>> {
    > >>> ns1::func2("abc");
    > >> I presume you mean ns1::func.

    >
    > >>> }
    > >>> -file2.cpp
    > >>> namespace ns1
    > >>> {
    > >>> void func()
    > >>> {
    > >>> printf("func in %s\n", __FILE__);
    > >>> }
    > >>> }
    > >>> ---end Example2---
    > >>> gcc: compiles and works
    > >>> VC++: compiles and works
    > >> This should have the same problem as the above. There is no
    > >> declaration of ns1::func visible when you compile main, so the
    > >> code shouldn't compile. (Again, the g++ I have here doesn't
    > >> compile it. The error message is:
    > >> names.cc:20: error: ‘func’ is not a member of ‘ns1’
    > >> Not perfect, either: `func' cannot be found in `ns1' would be
    > >> better.)

    >
    > >>> I'm rather confused. Does a friend function declaration make
    > >>> it as if it's also declared in the enclosing namespace?
    > >> No, but it did in pre-standard C++. (More correctly, it
    > >> injected the name into file scope---there weren't namespaces ini
    > >> pre-standard C++, so there was no namespace scope.)

    >
    > >> I forget the reason why the committee changed this. (I've been
    > >> told at least a half dozen times. Each time, I recognize that
    > >> it is valid, but end up forgetting exactly what it was.) There
    > >> was discussion concerning the possibility of breaking existing
    > >> code, but in practice, no one could figure out a possible use
    > >> for a friend function that didn't have an argument which
    > >> depended on the class it was a friend of, and with such an
    > >> argument, ADL finds the function, even if the declaration isn't
    > >> visible.

    >
    > > Thanks for this information. But at the same time, I find some curious
    > > statements in the c++ standard and some books:
    > > c++ standard 3.3/4
    > > In particular, elaborated-type-specifiers
    > > (3.3.1) and friend declarations (11.4) may introduce a (possibly not
    > > visible) name into an enclosing namespace;
    > > these restrictions apply to that region.

    >
    > > c++ standard 3.3.1/6
    > > [Note: friend declarations refer to functions or classes that are
    > > members of the nearest enclosing namespace,
    > > but they do not introduce new names into that namespace (7.3.1.2).

    >
    > Yeah, it's inconsistent.
    >
    > As far as I can recall there isn't an active issue on it, either.
    >
    > There should be.
    >
    > Cheers, & hth.,
    >


    I hope so. But maybe I misunderstand some statements in the C++
    standard. Not sure.
    WaterWalk, May 27, 2008
    #5
  6. WaterWalk

    James Kanze Guest

    On May 25, 8:32 am, "Alf P. Steinbach" <> wrote:
    > * WaterWalk:


    [...]
    > > Thanks for this information. But at the same time, I find some curious
    > > statements in the c++ standard and some books:
    > > c++ standard 3.3/4
    > > In particular, elaborated-type-specifiers
    > > (3.3.1) and friend declarations (11.4) may introduce a (possibly not
    > > visible) name into an enclosing namespace;
    > > these restrictions apply to that region.


    > > c++ standard 3.3.1/6
    > > [Note: friend declarations refer to functions or classes that are
    > > members of the nearest enclosing namespace,
    > > but they do not introduce new names into that namespace (7.3.1.2).


    > Yeah, it's inconsistent.


    > As far as I can recall there isn't an active issue on it, either.


    > There should be.


    Well, both quotes are from non-normative notes; there's no
    ambiguity in the normative requirements. But the first one
    should definitely be either corrected or dropped. And the
    second one seems a bit ambiguous as well to me: a friend
    declaration can introduce a new name into a namespace; it just
    doesn't make it visible. (But I think that there is a more
    general problem of vocabulary here.)

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, May 27, 2008
    #6
  7. WaterWalk

    James Kanze Guest

    On May 27, 10:18 am, James Kanze <> wrote:
    > On May 25, 8:32 am, "Alf P. Steinbach" <> wrote:
    >
    > > * WaterWalk:


    > [...]


    > > > Thanks for this information. But at the same time, I find some curious
    > > > statements in the c++ standard and some books:
    > > > c++ standard 3.3/4
    > > > In particular, elaborated-type-specifiers
    > > > (3.3.1) and friend declarations (11.4) may introduce a (possibly not
    > > > visible) name into an enclosing namespace;
    > > > these restrictions apply to that region.
    > > > c++ standard 3.3.1/6
    > > > [Note: friend declarations refer to functions or classes that are
    > > > members of the nearest enclosing namespace,
    > > > but they do not introduce new names into that namespace (7.3.1.2).

    > > Yeah, it's inconsistent.
    > > As far as I can recall there isn't an active issue on it, either.
    > > There should be.


    > Well, both quotes are from non-normative notes; there's no
    > ambiguity in the normative requirements. But the first one
    > should definitely be either corrected or dropped. And the
    > second one seems a bit ambiguous as well to me: a friend
    > declaration can introduce a new name into a namespace; it just
    > doesn't make it visible. (But I think that there is a more
    > general problem of vocabulary here.)


    While preparing to write up a request for an editorial change
    here, I reread the quoted passages in context, and realize that
    in context, they are quite clear: the friend declaration
    introduces the name into the enclosing namespace, but does not
    make it visible there.

    This also clears up the question of vocabulary: when the
    standard says that a name is "in" a given namespace, that means
    that the name (or the entity designated by the name) is a member
    of that namespace. When it speaks of scope, it uses the word
    visibility or visible. Thus, in the initial example:

    namespace NS {
    class Foo {
    friend void f() ;
    } ;
    }

    The friend declaration introduces the name f into the namespace
    NS, but does not make it visible (in scope) in the namespace NS.
    In other words, the declaration declares a fully qualified name
    ::NS::f(), but the declaration is (visible) in the scope of
    ::NS::Foo.

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, May 27, 2008
    #7
    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. Alexander Stippler

    nested classes and friend declaration

    Alexander Stippler, Jul 2, 2003, in forum: C++
    Replies:
    1
    Views:
    383
    Victor Bazarov
    Jul 2, 2003
  2. john smith
    Replies:
    1
    Views:
    1,909
    Victor Bazarov
    Aug 10, 2003
  3. eddiew_AUS
    Replies:
    18
    Views:
    642
    Andrey Tarasevich
    Jan 27, 2004
  4. Yu Lianqing
    Replies:
    1
    Views:
    636
    Leor Zolman
    Apr 4, 2004
  5. Peter
    Replies:
    2
    Views:
    272
    Öö Tiib
    Jun 6, 2013
Loading...

Share This Page