Trouble with operator overloading/type conversion

P

Philip Pemberton

Hi,
I've just been trying to get some (pretty badly written) code working
on a different compiler. Unfortunately, I've hit a problem. When the
code below is compiled under Borland C++ it (allegedly) works fine. If I
try and compile it with GNU G++, I get the following error report:

bug.cpp: In function `GF2Poly operator%(OddGF2Poly&, OddGF2Poly&)':
bug.cpp:21: call of overloaded `GF2Poly(OddGF2Poly&)' is ambiguous
bug.cpp:3: candidates are: GF2Poly::GF2Poly(const GF2Poly&)
bug.cpp:7: GF2Poly::GF2Poly(long unsigned int = 0)

Could someone please tell me what's going wrong and how I could fix the
problem and get this code to compile (and, preferably, run)? This is a
severely trimmed down version of the code I'm trying to get working.

--- CODE BEGINS
typedef unsigned long UL;

class GF2Poly {
public:
UL p;

GF2Poly(UL x = 0) { p = x; }
operator UL() { return (p); }
};

class OddGF2Poly {
public:
UL p;

operator UL() { return (p); }
operator GF2Poly() { return GF2Poly((p << 1) | 1); }
};

GF2Poly operator% (OddGF2Poly &xx, OddGF2Poly &yy)
{
return GF2Poly(yy);
}

int main(void) {
GF2Poly gfp;
OddGF2Poly ogp1, ogp2;

gfp = ogp1 % ogp2;
return 0;
}
--- CODE ENDS

Thanks,
Phil.
(e-mail address removed) (valid address)
http://www.philpem.me.uk/
 
G

Gianni Mariani

Philip Pemberton wrote:
....
Could someone please tell me what's going wrong and how I could fix the
problem and get this code to compile (and, preferably, run)? This is a
severely trimmed down version of the code I'm trying to get working.

--- CODE BEGINS
typedef unsigned long UL;

class GF2Poly {
public:
UL p;

Note that the compiler provides:

GF2Poly(const GF2Poly &)
GF2Poly(UL x = 0) { p = x; }
operator UL() { return (p); }
};

class OddGF2Poly {
public:
UL p;

operator UL() { return (p); }
operator GF2Poly() { return GF2Poly((p << 1) | 1); }

The danger of conversion operators is that you can create multiple
ambiguous conversions and hence you're required to specify them !
};

GF2Poly operator% (OddGF2Poly &xx, OddGF2Poly &yy)
{
return GF2Poly(yy);

Since you have 2 constructors (one that takes const GF2Poly & which
matches with the operator GF2Poly(), and another that matches with
operator UL(), the compiler can't choose (because the standard says so!).

You can either.

return GF2Poly(UL(yy));
or
return GF2Poly(yy.operator GF2Poly());

Ask yourself if you can remove the operators T() functions ...

At a guess, I would remove the operator UL() methods because it would be
much safer to use a method like:

UL Order()
{
return p;
}

.... and there would be no ambiguity.
}

int main(void) {
GF2Poly gfp;
OddGF2Poly ogp1, ogp2;

gfp = ogp1 % ogp2;
return 0;
}
--- CODE ENDS


BTW - good job on the code snippet !
 
V

Victor Bazarov

Philip Pemberton said:
Hi,
I've just been trying to get some (pretty badly written) code working on
a different compiler. Unfortunately, I've hit a problem. When the code
below is compiled under Borland C++ it (allegedly) works fine. If I try
and compile it with GNU G++, I get the following error report:

bug.cpp: In function `GF2Poly operator%(OddGF2Poly&, OddGF2Poly&)':
bug.cpp:21: call of overloaded `GF2Poly(OddGF2Poly&)' is ambiguous
bug.cpp:3: candidates are: GF2Poly::GF2Poly(const GF2Poly&)
bug.cpp:7: GF2Poly::GF2Poly(long unsigned int = 0)

Could someone please tell me what's going wrong and how I could fix the
problem and get this code to compile (and, preferably, run)? This is a
severely trimmed down version of the code I'm trying to get working.

The error comes from the attemps of the compiler to find a suitable
conversion from 'OddGF2Poly&' argument (yy) in order to create a GF2Poly.
Since the "functional type conversion" is used, the compiler probably
tries to consider only conversion by constructor as possible. The fix
is simple. See below.

--- CODE BEGINS
typedef unsigned long UL;

class GF2Poly {
public:
UL p;

GF2Poly(UL x = 0) { p = x; }
operator UL() { return (p); }
};

class OddGF2Poly {
public:
UL p;

operator UL() { return (p); }
operator GF2Poly() { return GF2Poly((p << 1) | 1); }
};

GF2Poly operator% (OddGF2Poly &xx, OddGF2Poly &yy)
{
return GF2Poly(yy);

Just drop the 'GF2Poly' making it

return yy;
 
D

DaKoadMunky

Just drop the 'GF2Poly' making it

return yy;

I am not familiar with "functional type conversion." I found no references to
it and C++ using Google.

Could you elaborate?

Doesn't the compiler still have the choice of two equally good conversions
available when constructing the return value?

This modified example still did not compile using VC++.NET. It said the call
to the GF2Poly ctor was ambiguous.
 
G

Gianni Mariani

DaKoadMunky said:
I am not familiar with "functional type conversion." I found no references to
it and C++ using Google.

C++ has a "conversion" operator facility that allows you to provide a
conversion function based on the type of the value being assigned.

i.e.

struct Y;
struct X{
operator Y(); // conversion function to convert an X to a Y
};

The problem you have is that it can introduce multiple ambiguous ways to
convert and the standard says that if there exists ambiguity, it is an
error.
Could you elaborate?

Doesn't the compiler still have the choice of two equally good conversions
available when constructing the return value?

2 equally good conversions is an error according to the standard.
This modified example still did not compile using VC++.NET. It said the call
to the GF2Poly ctor was ambiguous.

See my response to the OP.
 
D

DaKoadMunky

This modified example still did not compile using VC++.NET. It said the call
to the GF2Poly ctor was ambiguous.

I am quoting myself! Never done that before.

The Comeau Online Compiler accepted Victors modification.

That doesn't make it legal of course, but I generally assume that Comeau
implements the standard correctly.

So how is it that the change eliminates the ambiguity?

Also, I was thinking the original example contained two implicit conversion
sequences in one case and that it would select the path that contained only one
implicit conversion.

One possibility for the original example was...

OddGF2Poly - > int via OddGF2Poly::eek:perator int()
then
int -> GF2Poly via GF2Poly(int)

I thought only one conversion could be applied to make a call succeed.

How am I mistaken here?
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top