Non-conforming g++ and msvc for inline friend func? Help appreciated.

Discussion in 'C++' started by Alf P. Steinbach, May 4, 2010.

  1. Comeau compiles fine, g++ and msvc fail.


    <code file="x.cpp">
    #include <algorithm>

    namespace adl_is_bad {

    struct Foo
    {
    friend void swap( Foo&, Foo& ) {}
    };

    struct Bar
    {
    Foo myFoo;
    int myInt;

    Bar(): myInt( 0 ) {}

    friend void swap( Bar& a, Bar& b )
    {
    using namespace std;
    //sswap( a.myFoo, b.myFoo );
    swap( a.myInt, b.myInt );
    }
    };

    } // namespace adl_is_bad

    int main() {}
    </code>


    <comeau>
    Your Comeau C/C++ test results are as follows:

    Comeau C/C++ 4.3.10.1 (Oct 6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
    Copyright 1988-2008 Comeau Computing. All rights reserved.
    MODE:strict errors C++ C++0x_extensions


    In strict mode, with -tused, Compile succeeded (but remember, the Comeau online
    compiler does not link).
    Compiled with C++0x extensions enabled.
    </comeau>


    <g++ 4.4.1>
    C:\test> gnuc --version
    g++ (TDM-2 mingw32) 4.4.1
    Copyright (C) 2009 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


    C:\test> gnuc x.cpp
    x.cpp: In function 'void adl_is_bad::swap(adl_is_bad::Bar&, adl_is_bad::Bar&)':
    x.cpp:21: error: 'swap' was not declared in this scope

    C:\test> _
    </g++ 4.4.1>


    <msvc 7.1>
    C:\test> msvc --version
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.6030 for 80x86
    Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

    usage: cl [ option... ] filename... [ /link linkoption... ]

    C:\test> msvc x.cpp
    x.cpp
    x.cpp(21) : error C3767: 'swap' matching function is not accessible
    could be the friend function at 'x.cpp(7)' : 'swap' [may be found via
    argument-dependent lookup]
    or the friend function at 'x.cpp(17)' : 'swap' [may be found via
    argument-dependent lookup]

    C:\test> _
    </msvc 7.1>


    <msvc 9.0>
    C:\test> msvc --version
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
    Copyright (C) Microsoft Corporation. All rights reserved.

    usage: cl [ option... ] filename... [ /link linkoption... ]

    C:\test> msvc x.cpp
    x.cpp
    x.cpp(21) : error C2664: 'void adl_is_bad::swap(adl_is_bad::Bar
    &,adl_is_bad::Bar &)' : cannot convert parameter 1 from
    'int' to 'adl_is_bad::Bar &'

    C:\test> _
    </msvc 9.0>


    Which compiler is right, if any?

    Is there a commonly used solution for this?

    Or perhaps, just a solution?


    Cheers,

    - Alf
    Alf P. Steinbach, May 4, 2010
    #1
    1. Advertising

  2. Alf P. Steinbach

    Ian Collins Guest

    On 05/ 4/10 01:25 PM, Alf P. Steinbach wrote:
    > Comeau compiles fine, g++ and msvc fail.
    >
    >
    > <code file="x.cpp">
    > #include <algorithm>
    >
    > namespace adl_is_bad {
    >
    > struct Foo
    > {
    > friend void swap( Foo&, Foo& ) {}
    > };
    >
    > struct Bar
    > {
    > Foo myFoo;
    > int myInt;
    >
    > Bar(): myInt( 0 ) {}
    >
    > friend void swap( Bar& a, Bar& b )
    > {
    > using namespace std;
    > //sswap( a.myFoo, b.myFoo );
    > swap( a.myInt, b.myInt );
    > }
    > };
    >
    > } // namespace adl_is_bad
    >

    Sun CC also complains:

    Could not find a match for adl_is_bad::swap(int, int) needed in
    adl_is_bad::swap(adl_is_bad::Bar&, adl_is_bad::Bar&).

    > Which compiler is right, if any?


    I'll leave that bit to a language lawyer!

    > Is there a commonly used solution for this?


    Use "std::swap"?

    --
    Ian Collins
    Ian Collins, May 4, 2010
    #2
    1. Advertising

  3. On 04.05.2010 03:43, * Ian Collins:
    > On 05/ 4/10 01:25 PM, Alf P. Steinbach wrote:
    >> Comeau compiles fine, g++ and msvc fail.
    >>
    >>
    >> <code file="x.cpp">
    >> #include <algorithm>
    >>
    >> namespace adl_is_bad {
    >>
    >> struct Foo
    >> {
    >> friend void swap( Foo&, Foo& ) {}
    >> };
    >>
    >> struct Bar
    >> {
    >> Foo myFoo;
    >> int myInt;
    >>
    >> Bar(): myInt( 0 ) {}
    >>
    >> friend void swap( Bar& a, Bar& b )
    >> {
    >> using namespace std;
    >> //sswap( a.myFoo, b.myFoo );
    >> swap( a.myInt, b.myInt );
    >> }
    >> };
    >>
    >> } // namespace adl_is_bad
    >>

    > Sun CC also complains:
    >
    > Could not find a match for adl_is_bad::swap(int, int) needed in
    > adl_is_bad::swap(adl_is_bad::Bar&, adl_is_bad::Bar&).
    >
    >> Which compiler is right, if any?

    >
    > I'll leave that bit to a language lawyer!
    >
    >> Is there a commonly used solution for this?

    >
    > Use "std::swap"?


    Yeah, but imagine that the 'int' is a template parameter type.

    Then one wouldn't want to impose std::swap?


    Cheers,

    - Alf
    Alf P. Steinbach, May 4, 2010
    #3
  4. On 04.05.2010 03:43, * Ian Collins:
    > On 05/ 4/10 01:25 PM, Alf P. Steinbach wrote:
    >> Comeau compiles fine, g++ and msvc fail.
    >>
    >>
    >> <code file="x.cpp">
    >> #include <algorithm>
    >>
    >> namespace adl_is_bad {
    >>
    >> struct Foo
    >> {
    >> friend void swap( Foo&, Foo& ) {}
    >> };
    >>
    >> struct Bar
    >> {
    >> Foo myFoo;
    >> int myInt;
    >>
    >> Bar(): myInt( 0 ) {}
    >>
    >> friend void swap( Bar& a, Bar& b )
    >> {
    >> using namespace std;
    >> //sswap( a.myFoo, b.myFoo );
    >> swap( a.myInt, b.myInt );
    >> }
    >> };
    >>
    >> } // namespace adl_is_bad
    >>

    > Sun CC also complains:
    >
    > Could not find a match for adl_is_bad::swap(int, int) needed in
    > adl_is_bad::swap(adl_is_bad::Bar&, adl_is_bad::Bar&).
    >
    >> Which compiler is right, if any?

    >
    > I'll leave that bit to a language lawyer!


    OK, I'll post this to [comp.std.c++].


    Cheers, & thanks,

    - Alf
    Alf P. Steinbach, May 4, 2010
    #4
  5. "Alf P. Steinbach" <> writes:

    > Comeau compiles fine, g++ and msvc fail.
    >
    >
    > <code file="x.cpp">
    > #include <algorithm>
    >
    > namespace adl_is_bad {
    >
    > struct Foo
    > {
    > friend void swap( Foo&, Foo& ) {}
    > };
    >
    > struct Bar
    > {
    > Foo myFoo;
    > int myInt;
    >
    > Bar(): myInt( 0 ) {}
    >
    > friend void swap( Bar& a, Bar& b )
    > {
    > using namespace std;
    > //sswap( a.myFoo, b.myFoo );
    > swap( a.myInt, b.myInt );
    > }
    > };
    >
    > } // namespace adl_is_bad
    >
    > int main() {}
    > </code>
    >


    Just a quick question, while I think this through. I can accept that
    there is a question here about which compilers are performing correctly,
    but what has this to do with ADL? Your arguments to swap( a.myInt,
    b.myInt ) are (obviously) of type int; that is, they are of fundamental
    type. Given that, ADL applies... how?

    Regards

    Paul Bibbings
    Paul Bibbings, May 4, 2010
    #5
  6. "Alf P. Steinbach" <> writes:

    > Comeau compiles fine, g++ and msvc fail.
    >
    >
    > <code file="x.cpp">
    > #include <algorithm>
    >
    > namespace adl_is_bad {
    >
    > struct Foo
    > {
    > friend void swap( Foo&, Foo& ) {}
    > };
    >
    > struct Bar
    > {
    > Foo myFoo;
    > int myInt;
    >
    > Bar(): myInt( 0 ) {}
    >
    > friend void swap( Bar& a, Bar& b )
    > {
    > using namespace std;
    > //sswap( a.myFoo, b.myFoo );
    > swap( a.myInt, b.myInt );
    > }
    > };
    >
    > } // namespace adl_is_bad
    >
    > int main() {}
    > </code>
    >


    Just as a first thought, although I'm not offering this as `correct' in
    any sense, as I'm not near my copy of the Standard at the moment and
    will need to do some digging.

    Suppose, for the sake of a playing devils-advocate and attempting to
    support the compilers that fails this code, we look at the following:

    1. the inline definition of swap in struct Foo introduces swap(Foo&,
    Foo&) into namepspace adl_is_bad; that is:

    void adl_is_bad::swap(Foo&, Foo&)

    2. likewise, the inline definition of swap(Bar&, Bar&) in struct Bar
    introduces into adl_is_bad:

    void adl_is_bad::swap(Bar&, Bar&)

    Now - and this is the part that I will need to look up... Isn't it the
    case in name lookup that, when a name is found *directly*, other names
    introduced by using directives that might otherwise be found are *not*
    considered? I'll check this, but if it were the case, then the call to
    swap(a.myInt, b.myInt) from swap(Bar&, Bar&) would find both these
    declarations, but not std::swap, since that would not be considered
    owing to it being introduced via a using directive.

    These are just some thoughts prior to working out what's really going
    on, so please ignore if totally incorrect. :)

    Regards

    Paul Bibbings
    Paul Bibbings, May 4, 2010
    #6
  7. On 04.05.2010 16:06, * Paul Bibbings:
    > "Alf P. Steinbach"<> writes:
    >
    >> Comeau compiles fine, g++ and msvc fail.
    >>
    >>
    >> <code file="x.cpp">
    >> #include<algorithm>
    >>
    >> namespace adl_is_bad {
    >>
    >> struct Foo
    >> {
    >> friend void swap( Foo&, Foo& ) {}
    >> };
    >>
    >> struct Bar
    >> {
    >> Foo myFoo;
    >> int myInt;
    >>
    >> Bar(): myInt( 0 ) {}
    >>
    >> friend void swap( Bar& a, Bar& b )
    >> {
    >> using namespace std;
    >> //sswap( a.myFoo, b.myFoo );
    >> swap( a.myInt, b.myInt );
    >> }
    >> };
    >>
    >> } // namespace adl_is_bad
    >>
    >> int main() {}
    >> </code>
    >>

    >
    > Just a quick question, while I think this through. I can accept that
    > there is a question here about which compilers are performing correctly,
    > but what has this to do with ADL? Your arguments to swap( a.myInt,
    > b.myInt ) are (obviously) of type int; that is, they are of fundamental
    > type. Given that, ADL applies... how?


    First, the technique illustrated is in support of ADL. Otherwise there wouldn't
    be much point to doing it this way (indeed this possibility, not having to know
    whcih 'swap', is as I perceive it the most often cited argument in favor of
    ADL). Secondly, with MSVC 7.1 the error message specifically mentions ADL.

    So I guess that the intricacies ADL is part of the answer, but also perhaps
    namespace subtleties (putting the code in the global namespace => works!) and
    friend function injection subtleties & convoluted history of semantics changes.

    Anyway, I "solved" it by applying a workaround /convention/:

    * Every class supporting swapping defines a public method 'swapWith'.

    * Every such class also places a corresponding free 'swap' function in
    the global namespace.

    * To support the latter I defined a macro CPPX_IMPLEMENT_SWAP. :)

    Note: the original article has now been posted and published in [comp.std.c++].

    I think that's a better forum for this question.


    Cheers,

    - Alf
    Alf P. Steinbach, May 4, 2010
    #7
  8. "Alf P. Steinbach" <> writes:

    > On 04.05.2010 16:06, * Paul Bibbings:

    <snip />
    >> Just a quick question, while I think this through. I can accept that
    >> there is a question here about which compilers are performing correctly,
    >> but what has this to do with ADL? Your arguments to swap( a.myInt,
    >> b.myInt ) are (obviously) of type int; that is, they are of fundamental
    >> type. Given that, ADL applies... how?

    >
    > First, the technique illustrated is in support of ADL. Otherwise there
    > wouldn't be much point to doing it this way (indeed this possibility,
    > not having to know whcih 'swap', is as I perceive it the most often
    > cited argument in favor of ADL). Secondly, with MSVC 7.1 the error
    > message specifically mentions ADL.


    I'm not sure what your first statement means, that "the technique
    illustrated is in support of ADL." There is certainly the potential for
    the friend functions to be found using ADL, if that is what you mean.
    Then, as to your second point above, that is really all the VS error
    messages are reporting...

    > C:\test> msvc x.cpp
    > x.cpp
    > x.cpp(21) : error C3767: 'swap' matching function is not accessible
    > could be the friend function at 'x.cpp(7)' : 'swap' [may be
    > found via argument-dependent lookup]
    > or the friend function at 'x.cpp(17)' : 'swap' [may be
    > found via argument-dependent lookup]


    .... that is to say, that whilst the functions:

    adl_is_bad::swap(Foo&, Foo&) // line 7

    and:

    adl_is_bad::swap(Bar&, Bar&) // line 17

    `may be' found via argument-dependent lookup, they are *in fact* not
    considered simply for the point that I was trying to make; that, in your
    example, calling swap with *int* arguments, you are not actually
    invoking adl at all. Or... to soften that statement then, perhaps it's
    more correct to say that ADL /does/ apply, but that it cannot succeed
    nevertheless.

    In the context of ADL, as you know, the concepts of associated
    namespaces and associated classes are central. But of course, as
    [basic.koenig.lookup]/2 states:

    "If T is a fundamental type, its associated sets of namespaces and
    classes are both empty."

    Following from this, taking the viewpoint that ADL is being applied but
    that the set of associated namespaces and classes are both empty,
    perhaps [basic.koenig.lookup]/3 is being applied in the failing cases
    nevertheless. That is:

    "Any using-directives in the associated namespace are ignored."

    This, however, is not to support those implementations, since this point
    should not, IMHO, be relevant when the set is empty, as there are then
    *no* associated namespaces. But it may go some way to getting an
    insight into just what /might/ be going wrong. It looks possible that
    the error, if error there is, is that the implementations that reject
    your code, whilst finding the set of associated namespaces empty,
    nevertheless are continuing to reject the using directive (according to
    para 3) which would otherwise find std::swap.

    <snip />

    Regards

    Paul Bibbings
    Paul Bibbings, May 4, 2010
    #8
    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. Senthilraja
    Replies:
    7
    Views:
    569
    stelios xanthakis
    Oct 15, 2003
  2. Johnny
    Replies:
    3
    Views:
    443
    Robert Kern
    Aug 23, 2005
  3. Hari Sekhon
    Replies:
    0
    Views:
    494
    Hari Sekhon
    Jun 20, 2006
  4. Alex Vinokur
    Replies:
    6
    Views:
    343
    Tor Rustad
    Nov 18, 2006
  5. Öö Tiib
    Replies:
    0
    Views:
    643
    Öö Tiib
    May 4, 2010
Loading...

Share This Page