Error operator+ function

N

Nephi Immortal

I am trying to figure out why C++ Compiler generates an error message
as saying “3 overloads have similar conversions” It will compile
without any problem if I comment casting operator function. I still
need to use casting operator function and add operator function.


class A {
public:
A( unsigned int data ) : m_data( data ) {
}
~A() {
}

A( const A& r ) : m_data( r.m_data ) {
}

const A& operator=( const A& r ) {
m_data = r.m_data;
return *this;
}

const A& operator=( const unsigned int data ) {
m_data = data;
return *this;
}

// Compile without error if you comment below.
operator unsigned int() {
return m_data;
}

A operator+( const A& r ) {
A t( m_data );
t.m_data += r.m_data;
return t;
}

A operator+( const unsigned int data ) {
A t( m_data );
t.m_data += data;
return t;
}

A &operator+=( const A& r ) {
m_data += r.m_data;
return *this;
}

A &operator+=( const unsigned int data ) {
m_data += data;
return *this;
}

private:
unsigned int m_data;
};


int main () {
unsigned int x = 1, y = 2;

A d( x ), d2( y );
d = d + d2; // OK
d += d2; // OK

unsigned int data = d; // OK

d = d + 7; // ERROR
d += 7; // OK

return 0;
} // end function main

------ Build started: Project: MPU_65xx, Configuration: Debug Win32
------
Main.cpp
c:\ main.cpp(216): error C2666: 'A::eek:perator +' : 3 overloads have
similar conversions
c:\main.cpp(46): could be 'A A::eek:perator +(const unsigned
int)'
c:\main.cpp(41): or 'A &A::eek:perator +(const A &)'
or 'built-in C++ operator+(unsigned int, int)'
while trying to match the argument list '(A, int)'
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped
==========
 
I

Ian Collins

I am trying to figure out why C++ Compiler generates an error message
as saying “3 overloads have similar conversions” It will compile
without any problem if I comment casting operator function. I still
need to use casting operator function and add operator function.

Your problem is very similar to the earlier thread "cout printing and
function tracing".

You have to remove the ambiguity. For starters, making the constructor
from unsigned explicit removes one possible accidental conversion. Then
you can remove the operator + for unsigned. That leaves only one
possible sequence of conversions.

You could also remove the remaining operator + and use a free function:

A operator+( const A& a, const A& b )
{
A t(a);
t += b;
return t;
}

By the way, there's no point in declaring the unsigned parameters as const.
 
N

Nephi Immortal

Your problem is very similar to the earlier thread "cout printing and
function tracing".

You have to remove the ambiguity.  For starters, making the constructor
from unsigned explicit removes one possible accidental conversion.  Then
you can remove the operator + for unsigned.  That leaves only one
possible sequence of conversions.

You could also remove the remaining operator + and use a free function:

A operator+( const A& a, const A& b )
{
   A t(a);
   t += b;
   return t;

}

By the way, there's no point in declaring the unsigned parameters as const.

I discovered the solution. If you define “d = d + 7”, then C++
Compiler will generate an error message. Why? The constant value: 7
is signed integer by default in the main function’s body. You must
explicitly convert from signed integer to unsigned integer by doing “d
= d + ( unsigned int ) 7” or “d = d + 7U” before no error message
generates by C++ Compiler.
The alternative option is to add “A operator+( const int data )”
below “A operator+( const unsigned int data )”.
You do not need to place any operator functions on the global scope
since you prefer to treat them as member functions. The performance
should not be concerned as optimization is doing great job.
 
I

Ian Collins

I discovered the solution. If you define “d = d + 7”, then C++
Compiler will generate an error message. Why?

I assume you mean "write" rather than define?

The reason why is presence of the operator unsigned(). Thus d can be
converted to an unsigned which gives raise to the ambiguity between the
built in operator +(unsigned, int) and your A::eek:perator+.
The constant value: 7
is signed integer by default in the main function’s body. You must
explicitly convert from signed integer to unsigned integer by doing “d
= d + ( unsigned int ) 7” or “d = d + 7U” before no error message
generates by C++ Compiler.
The alternative option is to add “A operator+( const int data )”
below “A operator+( const unsigned int data )”.

Why add more code when you can also solve the problem by removing code?
You do not need to place any operator functions on the global scope
since you prefer to treat them as member functions. The performance
should not be concerned as optimization is doing great job.

Whether one uses a free function of a member to implement binary
operators is largely a matter of choice, performance does not enter into
the decision. Given an class with an operator +=, either is equally
valid. Given a set of classes with an operator +=, a simple template
function can be used for all of them:

template <typename T>
const T operator+( const T& a, const T& b )
{
return T(a) += b;
}
 
J

James Kanze

On 02/12/11 01:33 PM, Nephi Immortal wrote:
Your problem is very similar to the earlier thread "cout printing and
function tracing".
You have to remove the ambiguity. For starters, making the constructor
from unsigned explicit removes one possible accidental conversion. Then
you can remove the operator + for unsigned. That leaves only one
possible sequence of conversions.

But likely not the one he wants.
You could also remove the remaining operator + and use a free function:
A operator+( const A& a, const A& b )
{
A t(a);
t += b;
return t;
}

(For the expression d + 7, where d has type A, and type A has
both a constructor taking unsigned, and a conversion operator to
unsigned.)

How would that remove the ambiguity? You'd still have the two
possibilities: convert the A to unsigned, and use integer
arithmetic, or convert the int to A, and use the above. The
first results in a better match for the first argument, and the
second a better match for the second, so the expression is
ambiguous.

In such cases, the best solution is often to overload all three
possibilities:

A operator+( A const& lhs, A const& rhs );
A operator+( A const& lhs, unsigned rhs );
A operator+( unsigned lhs, A const& rhs );

This way, you get exactly what you want. (Somewhere floating
around I've got a template base class which does this
automatically if you define an A::eek:perator+=(unsigned rhs)
member. Something like:

template< typename DerivedType, typename SecondType >
class MixedArithmeticOperators
{
friend DerivedType operator+(
DerivedType const& lhs,
SecondType const& rhs )
{
DerivedType result(lhs);
result += rhs;
return result;
}
friend DerivedType operator+(
SecondType const& lhs,
DerivedType const& rhs )
{
DerivedType result(rhs);
result += lhs;
return result;
}
};

You'd then just derive from MixedArithmeticOperators<A,
unsigned>.
 
J

James Kanze

I discovered the solution. If you define “d = d + 7”, then C++
Compiler will generate an error message. Why? The constant value: 7
is signed integer by default in the main function’s body. You must
explicitly convert from signed integer to unsigned integer by doing “d
= d + ( unsigned int ) 7” or “d = d + 7U” before no error message
generates by C++ Compiler.

And what happens if you write 7 + t?

See my previous posting for the usual solution.
The alternative option is to add “A operator+( const int data )”
below “A operator+( const unsigned int data )”.
You do not need to place any operator functions on the global scope
since you prefer to treat them as member functions. The performance
should not be concerned as optimization is doing great job.

Binary arithmetic operators should never be members if the type
in question supports any type conversions. You want a + b to
behave in the same way for both a and b; the compiler will not
consider type conversions for the left hand side if the operator
is a member.

What book are you using to learn C++. This is one of the
basics, generally explained at about the same time operator
overloading is explained.
 
J

James Kanze

On 02/12/11 05:19 PM, Nephi Immortal wrote:
I assume you mean "write" rather than define?
The reason why is presence of the operator unsigned(). Thus d can be
converted to an unsigned which gives raise to the ambiguity between the
built in operator +(unsigned, int) and your A::eek:perator+.

I forgot to mention this earlier, but supporting bi-directional
implicit conversion (from and to the same type) is a good recepe
for ambiguities all over the place, and should generally be
avoided.
Why add more code when you can also solve the problem by removing code?

Probably because suppressing the conversion from unsigned A
causes the wrong operator+ to be used. More likely, he should
replace the explicit conversion to unsigned with a named member
function.
Whether one uses a free function of a member to implement binary
operators is largely a matter of choice,

Not really, when implicit conversions enter into the picture.
If operator+ is a member, implicit conversions will not be
considered for the left argument; this lack of orthogonality is
a serious defect for most types.
performance does not enter into
the decision. Given an class with an operator +=, either is equally
valid. Given a set of classes with an operator +=, a simple template
function can be used for all of them:
template <typename T>
const T operator+( const T& a, const T& b )
{
return T(a) += b;
}

First, such a template is going to result in an enormous number
of ambiguities. Second, it results in total uncontrolled
conversions. I far prefer the Barton and Nackman trick that I
posted in another response. But if you do want the uncontrolled
conversions, at least make this function a friend, and define it
inline in the class, so it won't be found except by ADL. (Note
that you make it a friend not so that it can access private
members, but so that you can define it completely within the
class, so no declarations will be visible outside the class
unless ADL kicks in.)
 
Ö

Öö Tiib

But likely not the one he wants.


(For the expression d + 7, where d has type A, and type A has
both a constructor taking unsigned, and a conversion operator to
unsigned.)

How would that remove the ambiguity?  You'd still have the two
possibilities: convert the A to unsigned, and use integer
arithmetic, or convert the int to A, and use the above.  The
first results in a better match for the first argument, and the
second a better match for the second, so the expression is
ambiguous.

In such cases, the best solution is often to overload all three
possibilities:

    A operator+( A const& lhs, A const& rhs );
    A operator+( A const& lhs, unsigned rhs );
    A operator+( unsigned lhs, A const& rhs );

This way, you get exactly what you want.  (Somewhere floating
around I've got a template base class which does this
automatically if you define an A::eek:perator+=(unsigned rhs)
member.  Something like:

    template< typename DerivedType, typename SecondType >
    class MixedArithmeticOperators
    {
        friend DerivedType operator+(
                DerivedType const& lhs,
                SecondType const& rhs )
        {
            DerivedType result(lhs);
            result += rhs;
            return result;
        }
        friend DerivedType operator+(
                SecondType const& lhs,
                DerivedType const& rhs )
        {
            DerivedType result(rhs);
            result += lhs;
            return result;
        }
    };

You'd then just derive from MixedArithmeticOperators<A,
unsigned>.

Seems good, but isn't it simpler to accept parameter by value if you
are otherwise going to copy it anyway? ...

template< typename Derived, typename Other >
class MixedArithmeticOperators
{
   friend Derived operator+( Derived lhs
, Other const& rhs )
  {
        lhs += rhs;
        return lhs;
    }

    friend Derived operator+( Other const& lhs
, Derived rhs )
    {
        rhs += lhs;
       return rhs;
   }
};
 
I

Ian Collins

But likely not the one he wants.

How do you know? Considering he doesn't even test the result! In this
example, it doesn't matter whether operator+(unsigned, int) or
A::eek:perator+(const A&) is called.
(For the expression d + 7, where d has type A, and type A has
both a constructor taking unsigned, and a conversion operator to
unsigned.)

How would that remove the ambiguity? You'd still have the two
possibilities: convert the A to unsigned, and use integer
arithmetic, or convert the int to A, and use the above. The
first results in a better match for the first argument, and the
second a better match for the second, so the expression is
ambiguous.

Not if the constructor from unsigned is explicit.
 
J

James Kanze

On Feb 12, 1:10 pm, James Kanze <[email protected]> wrote:

[...]
Seems good, but isn't it simpler to accept parameter by value
if you are otherwise going to copy it anyway? ...

Maybe. If you like revealing implementation details in the
interface:).

Seriously, in this case, you could argue both ways; the fact
that you copy it here is almost part of the contract (since the
contract says you use the += operator of DerivedType, and that
operator requires a non-const object). On the other hand, why
deviate from the general rule, especially in an inline
function, where it can make no possible difference with any
decent compiler.

(The "general" rule, almost universal in coding guidelines, is
use reference to const for class types, value for all others.
Arguably, this is premature optimization, and the rule should
be: use value, unless the profiler says otherwise. But this
general rule seems ubiquous, and I suspect that without it, the
profiler would say otherwise often enough to be more than a
little bothersome.)
template< typename Derived, typename Other >
class MixedArithmeticOperators
{
friend Derived operator+( Derived lhs
, Other const& rhs )
{
lhs += rhs;
return lhs;
}
friend Derived operator+( Other const& lhs
, Derived rhs )
{
rhs += lhs;
return rhs;
}
};

A third possiblity---one that I've seen more often than the
above, is:

template< typename DerivedType, typename SecondType >
class MixedArithmeticOperators
{
friend DerivedType operator+(
DerivedType const& lhs,
SecondType const& rhs )
{
return DerivedType(lhs) += rhs;
}
friend DerivedType operator+(
SecondType const& lhs,
DerivedType const& rhs )
{
return DerivedType(rhs) += lhs;
}
};

I'll admit that I don't like it too much; I don't like side
effects in a return statement. But it is the most succinct.

(BTW: I rather like your formatting, with the comma at the start
of the line, followed by a space. I've never been able to
convince anyone else to use it, however, and of course, I do
follow the local coding guidelines, always. Have you ever
succeeded in getting this style into the coding guidelines?)
 
J

James Kanze

On 02/13/11 12:10 AM, James Kanze wrote:

[...]
How do you know? Considering he doesn't even test the result! In this
example, it doesn't matter whether operator+(unsigned, int) or
A::eek:perator+(const A&) is called.

Just guessing, but in general, if you define an operator+ for a
class, you want it to be used when adding values of that class.
Not if the constructor from unsigned is explicit.

If the constructor from unsigned is explicit, then the
expression is unambiguous, regardless of whether the operator is
a member or not; there is only one operator+ which can be
called, and that is the built-in one. The reason for preferring
a non-member is so that 7 + d has the same behavior at the
interface level as d + 7. If d + 7 is legal, and 7 + d isn't,
then you're clearly abusing operator overloading.
 
Ö

Öö Tiib

On Feb 12, 1:10 pm, James Kanze <[email protected]> wrote:

    [...]




Seems good, but isn't it simpler to accept parameter by value
if you are otherwise going to copy it anyway? ...

Maybe.  If you like revealing implementation details in the
interface:).

I think it does not reveal the details too intrusively. ;-) At least
usage of the interface remains same be it value or const reference.
Seriously, in this case, you could argue both ways; the fact
that you copy it here is almost part of the contract (since the
contract says you use the += operator of DerivedType, and that
operator requires a non-const object).  On the other hand, why
deviate from the general rule, especially in an inline
function, where it can make no possible difference with any
decent compiler.

My point was that the implementation is slightly simpler because copy
is made when passing the parameter. The possible C++0x optimizations
(moving the value) do not matter that much.
(The "general" rule, almost universal in coding guidelines, is
use reference to const for class types, value for all others.
Arguably, this is premature optimization, and the rule should
be: use value, unless the profiler says otherwise.  But this
general rule seems ubiquous, and I suspect that without it, the
profiler would say otherwise often enough to be more than a
little bothersome.)

Yes, that rule is sort of optimization rule. It is likely made to ease
decision between various ways to pass parameters. It is fine rule in
general but when local copy is made anyway then passing by value is
simpler way to make such copy i think. Prefer simplicity when effect
is same ... it is also sort of omnipresent rule.
A third possiblity---one that I've seen more often than the
above, is:

    template< typename DerivedType, typename SecondType >
    class MixedArithmeticOperators
    {
        friend DerivedType operator+(
                DerivedType const& lhs,
                SecondType const& rhs )
        {
            return DerivedType(lhs) += rhs;
        }
        friend DerivedType operator+(
                SecondType const& lhs,
                DerivedType const& rhs )
        {
            return DerivedType(rhs) += lhs;
        }
    };

I'll admit that I don't like it too much; I don't like side
effects in a return statement.  But it is the most succinct.

Yes, it is compacted form of your example.
(BTW: I rather like your formatting, with the comma at the start
of the line, followed by a space.  I've never been able to
convince anyone else to use it, however, and of course, I do
follow the local coding guidelines, always.  Have you ever
succeeded in getting this style into the coding guidelines?)

Sometimes. Most like it in member initializer list for example. Modern
monitors are so wide that if a line needs breaking then it is perhaps
too complex anyway but most agree that operator at start of line makes
it easier to read. Some just don't care. I would probably like some
"canonical style" of C++. The C++ source in repository would be kept
in that style and individual formatting would be then about
configuring the clients and editors ... just like syntax highlighting
and coloring.
 

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,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top