From: Kris Prad on
Testing implicit conversions using this contrived code:

struct B;
struct A
{
A() {}
A(const B& ) // ------------ (1)
{
}
};

struct B
{
// casting: used if (1) is not available
operator A() // ------------- (2)
{
return A();
}
};


void TestImplicitConv()
{
B b;
A a1 = b; // ok, invokes (1)
A a2;
// VS2008 complains if there is no assignment op, ok on Comeau
a2 = b; // -------- (3)
}

Comeau accepts (3), but which one takes precedence? (1) or (2)?

VS2008 accepts this in any of the following cases:
-- (3) is changed to a2 = (A) b , i.e. explicit cast

-- if assignment op is defined in class A: A& operator=(const B& b)
(unlike Comeau)

-- if (1) is rermoved, in which case (2) is used even without explicit
cast

Is the compiler doing it right?


Kris

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Paul Bibbings on
Kris Prad <krisprad(a)yahoo.co.uk> writes:

> Testing implicit conversions using this contrived code:
>
> struct B;
> struct A
> {
> A() {}
> A(const B& ) // ------------ (1)
> {
> }
> };
>
> struct B
> {
> // casting: used if (1) is not available
> operator A() // ------------- (2)
> {
> return A();
> }
> };
>
>
> void TestImplicitConv()
> {
> B b;
> A a1 = b; // ok, invokes (1)
> A a2;
> // VS2008 complains if there is no assignment op, ok on Comeau
> a2 = b; // -------- (3)
> }

To be specific here, VS2008 is not /solely/ complaining about the lack
of a matching assignment op. To give the error message in full
(compiled using 2008 Express):

d:\CPPProjects\CLCPP>cl /EHsc -c implicit_conv.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01
for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.

implicit_conv.cpp
implicit_conv.cpp(24) : error C2679: binary '=' : no operator found
which takes a right-hand operand of type 'B' (or there is no
acceptable conversion)
implicit_conv.cpp(9): could be 'A &A::operator =(const A &)'
while trying to match the argument list '(A, B)'

More pertinent here is the second part of the error (rather than that
there is "no operator found which takes a right-hand operand of type
'B'"):

"(or there is no acceptable conversion)"

The compiler accepts the presence of the implicitly-defined default copy
assignment:

A& A::operator=(const A&)

but what it doesn't appear to be happy with is the fact that there might
be a valid conversion that will permit this to be called.

Note, also, that the compiler is *not* reporting that conversions are
available but that these are ambiguous.

>
> Comeau accepts (3)

as does gcc:

09:45:06 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-gcc-4.4.3 -c
implicit_conv.cpp

09:45:38 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $

and it is worth looking at how gcc is resolving this (in order to
provide an example, at least, against which to consider you next
question):

09:47:42 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $i686-pc-cygwin-gcc-4.4.3 -S
implicit_conv.cpp

09:48:00 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPP $cat implicit_conv.s

<snip />

__Z16TestImplicitConvv: ; void TestImplicitConv()
LFB7:
pushl %ebp
LCFI6:
movl %esp, %ebp
LCFI7:
subl $20, %esp
LCFI8:
leal -2(%ebp), %eax
movl %eax, (%esp)
call __ZN1Bcv1AEv ; B::operator A() / A a1 = b;
movb %al, -3(%ebp)
leal -4(%ebp), %eax
movl %eax, (%esp)
call __ZN1AC1Ev ; A::A() / A a2;
leal -2(%ebp), %eax
movl %eax, (%esp)
call __ZN1Bcv1AEv ; B::operator A() / a2 = b;
movb %al, -1(%ebp)
leal -1(%ebp), %edx
leal -4(%ebp), %eax
cmpl %eax, %edx
leave
ret
LFE7:

As I say, this is only by way of a comparative example, but it appears
to show (note: my assembler is not that good) that gcc is prefering
B::opA() to the converting constructor for both:

A a1 = b;

and:

a2 = b;

> , but which one takes precedence? (1) or (2)?

`Chapter and Verse' from the Standard is required here, which I do not
have access to at the present time. No doubt someone else will provide
this promptly.

> VS2008 accepts this in any of the following cases:
> -- (3) is changed to a2 = (A) b , i.e. explicit cast
>
> -- if assignment op is defined in class A: A& operator=(const B& b)
> (unlike Comeau)
>
> -- if (1) is rermoved, in which case (2) is used even without explicit
> cast
>
> Is the compiler doing it right?

I would suggest, strongly not.

Regards

Paul Bibbings

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]