ambiguous constructor? Is it right?

Z

Zeppe

Dear all,

I have the following problem, that I'll try to explain with a very
minimal example:

class A
{
};

class B
{
public:
B() { }
B(const A&) { }
B(const B&) { }
};

class C
{
public:
operator A() const { return A(); }
operator B() const { return B(); }
};

int main(){
const C& c = C();
B b = static_cast<B>(c);
return 0;
}


Basically, I would expect that casting a const C& to B would call the
operator B() of C and that the construction C -> B (through the copy
constructor) would be preferred to C -> A -> B. In Visual C++ 9 it
actually does so, but gcc complains that there is an ambiguity. Who's
right (I guess Visual c++) and, in case, how could I nicely work around
the problem?

Thanks!

Zeppe
 
B

Barry

Zeppe said:
Dear all,

I have the following problem, that I'll try to explain with a very
minimal example:

class A
{
};

class B
{
public:
B() { }
B(const A&) { }
B(const B&) { }
};

class C
{
public:
operator A() const { return A(); }
operator B() const { return B(); }
};

int main(){
const C& c = C();
B b = static_cast<B>(c);
return 0;
}


Basically, I would expect that casting a const C& to B would call the
operator B() of C and that the construction C -> B (through the copy

what makes "operator B()" have higher priority?
constructor) would be preferred to C -> A -> B. In Visual C++ 9 it
actually does so, but gcc complains that there is an ambiguity. Who's
right (I guess Visual c++) and, in case, how could I nicely work around
the problem?

gcc is right,
You can compile using VC with /Za option, which disables the extension,
and produces the compile error.
I know ya gonna complain. :)
 
Z

Zeppe

Barry said:
what makes "operator B()" have higher priority?

because I specified a method for the conversion of C into B, in C. I
would expect it to be called in the static cast. The other way (C->A->B)
implies one level of implicit conversion, doesn't it?
gcc is right,
You can compile using VC with /Za option, which disables the extension,
and produces the compile error.
I know ya gonna complain. :)

No, I'm not, just a little bit disappointed :) And what about a
workaround? Is the only way to solve this to clean up one of the two
conversion ways?

Regards,

Zeppe
 
B

Barry

Zeppe said:
because I specified a method for the conversion of C into B, in C. I
would expect it to be called in the static cast. The other way (C->A->B)
implies one level of implicit conversion, doesn't it?


No, I'm not, just a little bit disappointed :) And what about a
workaround? Is the only way to solve this to clean up one of the two
conversion ways?

I think it is, since it violates the standard.
 
J

James Kanze

According to §5.2.9/3 (static_cast):

Otherwise, an expression e can be explicitly converted
to a type T using a static_cast of the form
static_cast<T>(e) if the declaration T t(e); is
well-formed, for some invented temporary variable t
(8.5). The effect of such an explicit conversion is the
same as performing the declaration and initialization
and then using the temporary variable as the result of
the conversion. [...]

So overload resolution treats the expression as if it were:
B untamedTemp( c ) ;
(followed by B b( untamedTemp ) ;). B has two constructors, one
which takes a const A&, and one which takes a const B&. C can
convert (equally well) to one or the other.
I think it is, since it violates the standard.

The "work-around" is to not define so many implicit conversions.
Generally, too many implicit conversions will lead to
ambiguities. And even if it doesn't, it leads to code which is
hard to understand and to maintain.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top