Function declared before call but defined after - compilation fails

Discussion in 'C++' started by johnbrown105@hotmail.com, May 16, 2007.

  1. Guest

    Hello All,

    I am doing another exercise (I repeat, *exercise*). The (irrelevant to
    this
    discussion) point is to show that "You can inject a friend declaration
    into
    a namespace by declaring it within an enclosed class". I have done
    this
    successfully, but please consider the following program:

    //: C10:FriendInjection.cpp
    // From Thinking in C++, 2nd Edition
    // Available at http://www.BruceEckel.com
    // (c) Bruce Eckel 2000
    // Copyright notice in Copyright.txt
    namespace Me {
    class Us {
    //...
    public:
    friend void you();
    };
    }
    // 1
    void Me::you(){}

    int main() {
    Me::you();
    return 0;
    }

    // 2
    // defining you() after main() does not compile
    // void Me::you(){}
    ///:~
    /////////////////////////////////////////////////////////////////////////

    If Me::you() is *defined* at (2) after the call in main(), gcc 4.1.1
    says:
    "error: 'you' is not a member of 'Me'". If, instead, Me::you is
    *defined* at (1),
    then it compiles.

    MSVC++ Express compiles it either way without a problem, as expected.

    Surely this is a bug in gcc?
     
    , May 16, 2007
    #1
    1. Advertising

  2. Howard Guest

    <> wrote in message
    news:...
    > Hello All,
    >
    > I am doing another exercise (I repeat, *exercise*). The (irrelevant to
    > this
    > discussion) point is to show that "You can inject a friend declaration
    > into
    > a namespace by declaring it within an enclosed class". I have done
    > this
    > successfully, but please consider the following program:
    >
    > //: C10:FriendInjection.cpp
    > // From Thinking in C++, 2nd Edition
    > // Available at http://www.BruceEckel.com
    > // (c) Bruce Eckel 2000
    > // Copyright notice in Copyright.txt
    > namespace Me {
    > class Us {
    > //...
    > public:
    > friend void you();
    > };
    > }
    > // 1
    > void Me::you(){}
    >
    > int main() {
    > Me::you();
    > return 0;
    > }
    >
    > // 2
    > // defining you() after main() does not compile
    > // void Me::you(){}
    > ///:~
    > /////////////////////////////////////////////////////////////////////////
    >
    > If Me::you() is *defined* at (2) after the call in main(), gcc 4.1.1
    > says:
    > "error: 'you' is not a member of 'Me'". If, instead, Me::you is
    > *defined* at (1),
    > then it compiles.
    >
    > MSVC++ Express compiles it either way without a problem, as expected.
    >
    > Surely this is a bug in gcc?
    >


    Why?

    Declaring a function as a friend does not declare or define that function.
    It merely states that said function is a friend.

    In case (1), you're declaring *and* defining Me::you(). If you move that to
    after main() as in case (2), then when main() is compiled, Me::you() has not
    yet been declaredand so it's an error.

    -Howard
     
    Howard, May 16, 2007
    #2
    1. Advertising

  3. JLS Guest

    On May 16, 11:38 am, wrote:
    > Hello All,
    >
    > I am doing another exercise (I repeat, *exercise*). The (irrelevant to
    > this
    > discussion) point is to show that "You can inject a friend declaration
    > into
    > a namespace by declaring it within an enclosed class". I have done
    > this
    > successfully, but please consider the following program:
    >
    > //: C10:FriendInjection.cpp
    > // From Thinking in C++, 2nd Edition
    > // Available athttp://www.BruceEckel.com
    > // (c) Bruce Eckel 2000
    > // Copyright notice in Copyright.txt
    > namespace Me {
    > class Us {
    > //...
    > public:
    > friend void you();
    > };}
    >
    > // 1
    > void Me::you(){}
    >
    > int main() {
    > Me::you();
    > return 0;
    >
    > }
    >
    > // 2
    > // defining you() after main() does not compile
    > // void Me::you(){}
    > ///:~
    > /////////////////////////////////////////////////////////////////////////
    >
    > If Me::you() is *defined* at (2) after the call in main(), gcc 4.1.1
    > says:
    > "error: 'you' is not a member of 'Me'". If, instead, Me::you is
    > *defined* at (1),
    > then it compiles.
    >
    > MSVC++ Express compiles it either way without a problem, as expected.
    >
    > Surely this is a bug in gcc?


    What happens if you change it to

    int main() {
    Me::Us::you();
    return 0;

    I would have thought that the "Us" would be necessary.
     
    JLS, May 16, 2007
    #3
  4. Howard Guest

    "JLS" <> wrote in message
    news:...
    > On May 16, 11:38 am, wrote:
    >> Hello All,
    >>
    >> I am doing another exercise (I repeat, *exercise*). The (irrelevant to
    >> this
    >> discussion) point is to show that "You can inject a friend declaration
    >> into
    >> a namespace by declaring it within an enclosed class". I have done
    >> this
    >> successfully, but please consider the following program:
    >>
    >> //: C10:FriendInjection.cpp
    >> // From Thinking in C++, 2nd Edition
    >> // Available athttp://www.BruceEckel.com
    >> // (c) Bruce Eckel 2000
    >> // Copyright notice in Copyright.txt
    >> namespace Me {
    >> class Us {
    >> //...
    >> public:
    >> friend void you();
    >> };}
    >>
    >> // 1
    >> void Me::you(){}
    >>
    >> int main() {
    >> Me::you();
    >> return 0;
    >>
    >> }
    >>
    >> // 2
    >> // defining you() after main() does not compile
    >> // void Me::you(){}
    >> ///:~
    >> /////////////////////////////////////////////////////////////////////////
    >>
    >> If Me::you() is *defined* at (2) after the call in main(), gcc 4.1.1
    >> says:
    >> "error: 'you' is not a member of 'Me'". If, instead, Me::you is
    >> *defined* at (1),
    >> then it compiles.
    >>
    >> MSVC++ Express compiles it either way without a problem, as expected.
    >>
    >> Surely this is a bug in gcc?

    >
    > What happens if you change it to
    >
    > int main() {
    > Me::Us::you();
    > return 0;
    >
    > I would have thought that the "Us" would be necessary.
    >


    Huh? The function you() is not a member of Us. It's a *friend* of Us.

    -Howard
     
    Howard, May 16, 2007
    #4
  5. BigBrian Guest

    > Surely this is a bug in gcc?

    gcc 4.0.1 compiles it either way for me.
     
    BigBrian, May 16, 2007
    #5
  6. Guest

    On May 16, 11:16 am, "Howard" <> wrote:
    > <> wrote in message
    >
    > Why?
    >
    > Declaring a function as a friend does not declare or define that function.
    > It merely states that said function is a friend.
    >
    > In case (1), you're declaring *and* defining Me::you(). If you move that to
    > after main() as in case (2), then when main() is compiled, Me::you() has not
    > yet been declared and so it's an error.
    >
    > -Howard


    Bruce Eckel has this to say in his book:

    "Notice the two other friend functions. The first declares an ordinary
    global function g( ) as a friend. But g( ) has not been previously
    declared at the global scope! It turns out that friend can be used
    this way to simultaneously declare the function *and* give it friend
    status."

    Of course, he could be wrong, but then again, so could you. I have not
    read the standards myself, and I probably never will. Who agrees with
    Bruce? With Howard?
     
    , May 16, 2007
    #6
  7. James Kanze Guest

    On May 16, 5:38 pm, wrote:

    > I am doing another exercise (I repeat, *exercise*). The
    > (irrelevant to this discussion) point is to show that "You can
    > inject a friend declaration into a namespace by declaring it
    > within an enclosed class".


    This is not up to date. Originally, a name declared in a friend
    declaration was injected into the enclosing namespace (or file
    scope, as it was then). This was changed in the standard, and
    friend names are no longer injected.

    > I have done this successfully, but
    > please consider the following program:


    > //: C10:FriendInjection.cpp
    > // From Thinking in C++, 2nd Edition
    > // Available athttp://www.BruceEckel.com
    > // (c) Bruce Eckel 2000
    > // Copyright notice in Copyright.txt
    > namespace Me {
    > class Us {
    > //...
    > public:
    > friend void you();
    > };}


    > // 1
    > void Me::you(){}


    > int main() {
    > Me::you();
    > return 0;
    >
    > }


    This should not compile with an up-to-date compiler. Bruce
    Eckel doubtlessly learned C++ before the change:).

    This would be legal according to the ARM, if you dropped the
    namespace. I suspect that there were also many compilers which
    supported it when they first introduced namespace as well.

    > // 2
    > // defining you() after main() does not compile
    > // void Me::you(){}
    > ///:~
    > /////////////////////////////////////////////////////////////////////////


    > If Me::you() is *defined* at (2) after the call in main(), gcc 4.1.1
    > says:
    > "error: 'you' is not a member of 'Me'". If, instead, Me::you is
    > *defined* at (1),
    > then it compiles.


    > MSVC++ Express compiles it either way without a problem, as expected.


    > Surely this is a bug in gcc?


    I wouldn't call it a bug. Technically, g++ is correct,
    according to the standard. MSV++ is correct, according to
    pre-standard conventions.

    In practice, it's hard to conceive of a real program where the
    change makes a difference. The most typical use of the friend
    function is for operator's, which have a parameter of the class
    type, and in this case, ADL now picks up the name. (ADL wasn't
    present in earlier C++.) FWIW: this change broke none of my
    earlier C++ (although other changes did).

    --
    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 16, 2007
    #7
  8. Guest

    On May 16, 12:22 pm, BigBrian <> wrote:
    > > Surely this is a bug in gcc?

    >
    > gcc 4.0.1 compiles it either way for me.


    As does gcc-3.4.2, OpenWatcom 1.6 and DigitalMars 8.49. For what it's
    worth, the Comeau compiler (with default options) at
    http://www.comeaucomputing.com/tryitout/ likes neither (1) nor (2).

    So Howard, does your compiler reject (2), as you say it should?
     
    , May 16, 2007
    #8
  9. Howard Guest

    <> wrote in message
    news:...
    > On May 16, 12:22 pm, BigBrian <> wrote:
    >> > Surely this is a bug in gcc?

    >>
    >> gcc 4.0.1 compiles it either way for me.

    >
    > As does gcc-3.4.2, OpenWatcom 1.6 and DigitalMars 8.49. For what it's
    > worth, the Comeau compiler (with default options) at
    > http://www.comeaucomputing.com/tryitout/ likes neither (1) nor (2).
    >
    > So Howard, does your compiler reject (2), as you say it should?
    >


    Nope. VC++ (from Visual Studio 2003) accepts it either way. But the
    question is what does the standard say, not what does Microsoft (or any
    other vendor) say. I don't have the standard handy (and I have a great deal
    of trouble understanding its legalese style), but I think James Kanze's
    answer covers it pretty well.

    -Howard
     
    Howard, May 16, 2007
    #9
  10. Guest

    On May 16, 3:39 pm, James Kanze <> wrote:
    > On May 16, 5:38 pm, wrote:
    >
    > > I am doing another exercise (I repeat, *exercise*). The
    > > (irrelevant to this discussion) point is to show that "You can
    > > inject a friend declaration into a namespace by declaring it
    > > within an enclosed class".

    >
    > This is not up to date. Originally, a name declared in a friend
    > declaration was injected into the enclosing namespace (or file
    > scope, as it was then). This was changed in the standard, and
    > friend names are no longer injected.
    >


    I see. Well, the book is old ((c) 2000) and the compilers mentioned in
    my later post are also old (mostly).
    >
    ><cut>
    >
    > I wouldn't call it a bug. Technically, g++ is correct,
    > according to the standard. MSV++ is correct, according to
    > pre-standard conventions.
    >

    <cut>
    The most typical use of the friend
    > function is for operator's, which have a parameter of the class
    > type, and in this case, ADL now picks up the name. (ADL wasn't
    > present in earlier C++.)


    Is this "ADL" why the mighty Comeau compiler accepts neither (1) nor
    (2)?
     
    , May 17, 2007
    #10
  11. James Kanze Guest

    On May 17, 4:35 am, wrote:
    > On May 16, 3:39 pm, James Kanze <> wrote:


    > > On May 16, 5:38 pm, wrote:


    > > > I am doing another exercise (I repeat, *exercise*). The
    > > > (irrelevant to this discussion) point is to show that "You can
    > > > inject a friend declaration into a namespace by declaring it
    > > > within an enclosed class".


    > > This is not up to date. Originally, a name declared in a friend
    > > declaration was injected into the enclosing namespace (or file
    > > scope, as it was then). This was changed in the standard, and
    > > friend names are no longer injected.


    > I see. Well, the book is old ((c) 2000) and the compilers mentioned in
    > my later post are also old (mostly).


    Exactly. In 2000, the standard was still very new, and most
    compilers still implemented the pre-standard rules from the ARM.

    I suspect that some compilers still implement them today, and
    will continue to implement them, in order to avoid breaking
    existing code. The vendors of other compilers may decide that
    the amount of code actually involved is small enough to not be
    worth the bother---as I said, if the function has parameters,
    the compiler will find it under the new rules because of ADL.
    And some vendors don't care about their customers code anyway,
    and don't mind breaking it.

    > ><cut>


    > > I wouldn't call it a bug. Technically, g++ is correct,
    > > according to the standard. MSV++ is correct, according to
    > > pre-standard conventions.


    > <cut>
    > The most typical use of the friend


    > > function is for operator's, which have a parameter of the class
    > > type, and in this case, ADL now picks up the name. (ADL wasn't
    > > present in earlier C++.)


    > Is this "ADL" why the mighty Comeau compiler accepts neither (1) nor
    > (2)?


    I'd have to see the exact error message to comment. The
    standard is not always very clear, but if I understand it
    correctly:

    namespace N {
    class C
    {
    friend void f() ;
    } ;
    }

    Says that there exists a function void N::f(), and that it is a
    friend of N::C, but it does not make this name visible outside
    of the class.

    The problem is probably:

    void N::f() {}

    According to the standard (§8.3): "When the declarator-id is
    qualified, the declaration shall refer to a previously declared
    member of the class or namespace to which the qualifier
    refers,[...]". This seems to be saying that the above statement
    is only legal if there is already a visible declaration of
    N::f(). And there isn't. But the wording is anything but
    clear.

    The "usual" way of doing this is something like:

    namespace N {
    class C
    {
    friend void f() ;
    } ;
    extern void f() ;
    }

    This would typically be in a header, and the definition of
    N::f() would be an a source file elsewhere; where really doesn't
    matter. If you do this, there should be no problems.

    And ADL has nothing to do with it, of course. ADL (argument
    dependent lookup) only enters into play when the function has
    arguments.

    --
    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 17, 2007
    #11
  12. Guest

    On May 17, 4:58 pm, James Kanze <> wrote:
    > The problem is probably:
    >
    > void N::f() {}
    >


    Comeau says:
    Comeau C/C++ 4.3.9 (Mar 27 2007 17:24:47) for ONLINE_EVALUATION_BETA1
    Copyright 1988-2007 Comeau Computing. All rights reserved.
    MODE:strict errors C++ C++0x_extensions

    "ComeauTest.c", line 15: error: namespace "Me" has no member "you"
    void Me::you(){}
    ^

    "ComeauTest.c", line 18: error: namespace "Me" has no member "you"
    Me::you();
    ^

    2 errors detected in the compilation of "ComeauTest.c".

    In strict mode, with -tused, Compile failed

    These messages mean what they say, if 'friend' no longer injects a
    name into an enclosing namespace.

    Line 15 is the definition 'void Me::you(){}' above main()
    Line 18 is the call 'Me::you();' in main()

    All is clear. Thank you.
     
    , May 18, 2007
    #12
    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. Oodini
    Replies:
    1
    Views:
    1,802
    Keith Thompson
    Sep 27, 2005
  2. Replies:
    9
    Views:
    371
    shish
    May 2, 2007
  3. Tagore

    function declared, but not defined

    Tagore, Jul 23, 2010, in forum: C Programming
    Replies:
    7
    Views:
    2,966
    Sebastian
    Jul 26, 2010
  4. Alok
    Replies:
    3
    Views:
    268
  5. Shriramana Sharma
    Replies:
    5
    Views:
    196
    Keith Thompson
    Apr 17, 2013
Loading...

Share This Page