Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Non-conforming g++ and msvc for inline friend func? Help appreciated. (http://www.velocityreviews.com/forums/t722111-non-conforming-g-and-msvc-for-inline-friend-func-help-appreciated.html)

Alf P. Steinbach 05-04-2010 01:25 AM

Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
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

Ian Collins 05-04-2010 01:43 AM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
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

Alf P. Steinbach 05-04-2010 02:14 AM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
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 05-04-2010 02:18 AM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
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

Paul Bibbings 05-04-2010 02:06 PM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
"Alf P. Steinbach" <alfps@start.no> 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 05-04-2010 02:21 PM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
"Alf P. Steinbach" <alfps@start.no> 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

Alf P. Steinbach 05-04-2010 07:12 PM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
On 04.05.2010 16:06, * Paul Bibbings:
> "Alf P. Steinbach"<alfps@start.no> 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

Paul Bibbings 05-04-2010 08:41 PM

Re: Non-conforming g++ and msvc for inline friend func? Help appreciated.
 
"Alf P. Steinbach" <alfps@start.no> 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


All times are GMT. The time now is 02:13 AM.

Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57