471,593 Members | 1,789 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,593 software developers and data experts.

why no ambiguity error generated

consider the following program:

#include <iostream>

using namespace std;

class my_complex
{
public:
friend ostream & operator<<(ostream &os, const my_complex &c);
my_complex(double r, double i = 10.0) : re(r), im(i) { }
my_complex(const my_complex &rc) : re(rc.re), im(rc.im) { }
my_complex operator+(const my_complex &r);
friend my_complex operator+(const my_complex &c1, const
my_complex &c2);

private:
double re;
double im;
};

ostream & operator<<(ostream &os, const my_complex &c)
{
os << "re = " << c.re << " im = " << c.im << endl;
return os;
}

my_complex my_complex::operator+(const my_complex &r)
{
cout << "from member operator+" << endl;
return my_complex(re + r.re, im + r.im);
}

my_complex operator+(const my_complex &c1, const my_complex &c2)
{
cout << "from friend operator+" << endl;
my_complex c(c1.re + c2.re, c1.im + c2.im);
return c;
}

int main()
{
my_complex obj(1, 2);

cout << 5.0 + obj;

cout << obj + 5.0;

return 0;
}

The output of the above program under both VC++2005 Express Edition
and g++, is

from friend operator+
re = 6 im = 12
from member operator+
re = 6 im = 12

I thought ambiguity error would be generated for the expressions '5.0
+ obj' and 'obj + 5.0' because I have defined operator+() both as
member function and as friend function. But my understanding seems to
be wrong. Kindly clarify where I am going wrong.

Thanks
V.Subramanian
Dec 3 '07 #1
10 2015
On Dec 3, 7:21 pm, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
consider the following program:

#include <iostream>

using namespace std;

class my_complex
{
public:
friend ostream & operator<<(ostream &os, const my_complex &c);
my_complex(double r, double i = 10.0) : re(r), im(i) { }
my_complex(const my_complex &rc) : re(rc.re), im(rc.im) { }
my_complex operator+(const my_complex &r);
friend my_complex operator+(const my_complex &c1, const
my_complex &c2);

private:
double re;
double im;

};

ostream & operator<<(ostream &os, const my_complex &c)
{
os << "re = " << c.re << " im = " << c.im << endl;
return os;

}

my_complex my_complex::operator+(const my_complex &r)
{
cout << "from member operator+" << endl;
return my_complex(re + r.re, im + r.im);

}

my_complex operator+(const my_complex &c1, const my_complex &c2)
{
cout << "from friend operator+" << endl;
my_complex c(c1.re + c2.re, c1.im + c2.im);
return c;

}

int main()
{
my_complex obj(1, 2);

cout << 5.0 + obj;

cout << obj + 5.0;

return 0;

}

The output of the above program under both VC++2005 Express Edition
and g++, is

from friend operator+
re = 6 im = 12
from member operator+
re = 6 im = 12

I thought ambiguity error would be generated for the expressions '5.0
+ obj' and 'obj + 5.0' because I have defined operator+() both as
member function and as friend function. But my understanding seems to
be wrong. Kindly clarify where I am going wrong.
It is not an ambiguity because of const-correctness. The member is not
a const member function. Because of that the first implicit 'this'
argument is non-const. While for the friend function, both arguments
are const. So, there's your difference. Make the member const and you
will find the ambiguity.
Dec 3 '07 #2
* On Dec 3, 7:37 pm, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
On Dec 3, 7:21 pm, "subramanian10...@yahoo.com, India"
Now I have made both the object as well as the operator+() member
function as const. ie consider the modified program:

#include <iostream>

using namespace std;

class my_complex
{
public:
friend ostream & operator<<(ostream &os, const my_complex &c);
my_complex(double r, double i = 10.0) : re(r), im(i) { }
my_complex(const my_complex &rc) : re(rc.re), im(rc.im) { }
my_complex operator+(const my_complex &r) const;
friend my_complex operator+(const my_complex &c1, const my_complex
&c2);

private:
double re;
double im;
};

ostream & operator<<(ostream &os, const my_complex &c)
{
os << "re = " << c.re << " im = " << c.im << endl;
return os;
}

my_complex my_complex::operator+(const my_complex &r) const
{
cout << "from member operator+" << endl;
return my_complex(re + r.re, im + r.im);
}

my_complex operator+(const my_complex &c1, const my_complex &c2)
{
cout << "from friend operator+" << endl;
my_complex c(c1.re + c2.re, c1.im + c2.im);
return c;
}

int main()
{
const my_complex obj(1, 2);

cout << 5.0 + obj;

// cout << obj + 5.0;

return 0;
}

While I am getting ambiguity error now for the commented statement,
there is still NO AMBIGUITY error generated for
'5.0 + obj'. I just now found in page 264 in the book "C++ FAQs" 2nd
Edition by Marshall Cline that C++ never promotes the 'this' object in
a member function invocation. If this is the reason(for no ambiguity),
then please explain why this rule is so - ie why a member function is
not called after promoting the 'this' object ?

If there is any other reason, kindly explain.

Thanks
V.Subramanian
Dec 4 '07 #3
On Dec 4, 10:09 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
* On Dec 3, 7:37 pm, Abhishek Padmanabh <abhishek.padman...@gmail.com>

<snipped code>

While I am getting ambiguity error now for the commented statement,
there is still NO AMBIGUITY error generated for
'5.0 + obj'. I just now found in page 264 in the book "C++ FAQs" 2nd
Edition by Marshall Cline that C++ never promotes the 'this' object in
a member function invocation. If this is the reason(for no ambiguity),
then please explain why this rule is so - ie why a member function is
not called after promoting the 'this' object ?

If there is any other reason, kindly explain.
I am not sure on this. That could be the reason as I could not find
anything specific regarding this in the standards (don't blame it,
blame me. I just could not find it, it must be there somewhere).
However, I am failing to see where the 'this' object promotion is
required.
Dec 4 '07 #4
su**************@yahoo.com wrote:
* On Dec 3, 7:37 pm, Abhishek Padmanabh <abhishek.padman...@gmail.com>
wrote:
>On Dec 3, 7:21 pm, "subramanian10...@yahoo.com, India"

Now I have made both the object as well as the operator+() member
function as const. ie consider the modified program:

#include <iostream>

using namespace std;

class my_complex
{
public:
friend ostream & operator<<(ostream &os, const my_complex &c);
my_complex(double r, double i = 10.0) : re(r), im(i) { }
my_complex(const my_complex &rc) : re(rc.re), im(rc.im) { }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is really unnecessary.
my_complex operator+(const my_complex &r) const;
friend my_complex operator+(const my_complex &c1, const my_complex
&c2);

private:
double re;
double im;
};
[..]

int main()
{
const my_complex obj(1, 2);

cout << 5.0 + obj;

// cout << obj + 5.0;

return 0;
}

While I am getting ambiguity error now for the commented statement,
there is still NO AMBIGUITY error generated for
'5.0 + obj'. I just now found in page 264 in the book "C++ FAQs" 2nd
Edition by Marshall Cline that C++ never promotes the 'this' object in
a member function invocation.
I believe you're misinterpreting something in the book. C++ never
seeks out conversions for the left operand for any binary operator.
That's the reason why '5.0 + obj' is never resolved to the member
function because double (the type of '5.0') does not have members.
If this is the reason(for no ambiguity),
then please explain why this rule is so - ie why a member function is
not called after promoting the 'this' object ?
There is no "promoting the 'this' object". The compiler finds two
(or more) operator+() functions in the global namespace. Only then
it tries to find the correct types to which to convert the operands
(arguments). Since 'my_complex' cannot be converted to 'double',
::operator+(double,double) cannot be used. But '5.0' can be converted
to 'my_complex', so ::operator+(my_complex const&, my_complex const&)
is a viable function.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 4 '07 #5
On Dec 3, 3:21 pm, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
consider the following program:
#include <iostream>
using namespace std;
class my_complex
{
public:
friend ostream & operator<<(ostream &os, const my_complex &c);
my_complex(double r, double i = 10.0) : re(r), im(i) { }
my_complex(const my_complex &rc) : re(rc.re), im(rc.im) { }
my_complex operator+(const my_complex &r);
friend my_complex operator+(const my_complex &c1, const
my_complex &c2);
private:
double re;
double im;
};
ostream & operator<<(ostream &os, const my_complex &c)
{
os << "re = " << c.re << " im = " << c.im << endl;
return os;
}
my_complex my_complex::operator+(const my_complex &r)
{
cout << "from member operator+" << endl;
return my_complex(re + r.re, im + r.im);
}
my_complex operator+(const my_complex &c1, const my_complex &c2)
{
cout << "from friend operator+" << endl;
my_complex c(c1.re + c2.re, c1.im + c2.im);
return c;
}
int main()
{
my_complex obj(1, 2);
cout << 5.0 + obj;
cout << obj + 5.0;
return 0;
}
The output of the above program under both VC++2005 Express Edition
and g++, is
from friend operator+
re = 6 im = 12
from member operator+
re = 6 im = 12
I thought ambiguity error would be generated for the expressions '5.0
+ obj' and 'obj + 5.0' because I have defined operator+() both as
member function and as friend function. But my understanding seems to
be wrong. Kindly clarify where I am going wrong.
The rule is actually fairly simple (in this case---I won't
pretend that overload resolution is simple in the absolute). In
the first case ("5.0 + obj"), the member operator cannot be
called. The rule is that a member function cannot be called on
a temporary which results from an implicit conversion. (Note
that "my_complex( 5.0 ) + obj" will call the member function.)
The reason for this rule is simple: allowing implcit conversions
here would be too error prone; the programmer expects member
functions to be called on a specific object.

In the second case, both functions can be called. The member
function is chosen, because it is non-const, and the object it
is being called on is non-const.

Note that the rule which applies in the first expression is
usually used to simulate the distinction between requiring an
lvalue or not for the operators. The rules aren't quite the
same, but the effects are similar enough: if a binary operator
requires an lvalue as its right argument, or a unary operator
requires an lvalue as its only argument, it is declared a member
(and thus, must be called on an existing object); if not, it is
declared as a free function (and thus all possible conversions
are taken into account). There are still some differences:
static_cast< double >( i ) += 3.2 is illegal, but static_cast<
my_complex >( i ) += 3.2 would pass. But it's close enough to
prevent casual errors.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Dec 4 '07 #6
* On Dec 4, 8:48 pm, James Kanze <james.ka...@gmail.comwrote:
On Dec 3, 3:21 pm, "subramanian10...@yahoo.com, India"
cout << 5.0 + obj;
The rule is that a member function cannot be called on
a temporary which results from an implicit conversion. (Note
that "my_complex( 5.0 ) + obj" will call the member function.)
The reason for this rule is simple: allowing implcit conversions
here would be too error prone; the programmer expects member
functions to be called on a specific object.
--
James Kanze (GABI Software)
Is my following understanding of the reason you have stated for the
above rule correct ?

While evaluating the expression 5.0 + obj, if implicit conversion is
allowed, then the compiler may not know which type it should convert
5.0 to.

Kindly clarify with an example.

Thanks
V.Subramanian
Dec 5 '07 #7
* On Dec 5, 3:48 pm, James Kanze <james.ka...@gmail.comwrote:
On Dec 5, 7:55 am, "subramanian10...@yahoo.com, India"

<subramanian10...@yahoo.comwrote:
* On Dec 4, 8:48 pm, James Kanze <james.ka...@gmail.comwrote:
On Dec 3, 3:21 pm, "subramanian10...@yahoo.com, India"
cout << 5.0 + obj;
The rule is that a member function cannot be called on
a temporary which results from an implicit conversion. (Note
that "my_complex( 5.0 ) + obj" will call the member function.)
The reason for this rule is simple: allowing implicit conversions
here would be too error prone; the programmer expects member
functions to be called on a specific object.
Kindly bear with me for asking the same question regarding 5.0 + obj.
I still am not able to understand the rule that a member function
cannot be called on a temporary which results from an implicit
conversion. why implicit conversion here is error-prone. Kindly give
an example.

Thanks
V.Subramanian
Dec 5 '07 #8
su**************@yahoo.com wrote:
* On Dec 5, 3:48 pm, James Kanze <james.ka...@gmail.comwrote:
>On Dec 5, 7:55 am, "subramanian10...@yahoo.com, India"

<subramanian10...@yahoo.comwrote:
>>* On Dec 4, 8:48 pm, James Kanze <james.ka...@gmail.comwrote:
On Dec 3, 3:21 pm, "subramanian10...@yahoo.com, India"
cout << 5.0 + obj;
The rule is that a member function cannot be called on
a temporary which results from an implicit conversion. (Note
that "my_complex( 5.0 ) + obj" will call the member function.)
The reason for this rule is simple: allowing implicit conversions
here would be too error prone; the programmer expects member
functions to be called on a specific object.

Kindly bear with me for asking the same question regarding 5.0 + obj.
I still am not able to understand the rule that a member function
cannot be called on a temporary which results from an implicit
conversion. why implicit conversion here is error-prone. Kindly give
an example.
The answer is simple: because the Standard prohibits that. Please
kindly see Standard, [over.match.oper] (13.3.1.2 in the latest).

Temporaries are created when they are required, not on a whim of
the compiler. If you see the expression 1+2, and both 1 and 2 can
be converted to 'A', why don't they? Kindly use your head.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dec 5 '07 #9
On Dec 5, 3:53 pm, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
* On Dec 5, 3:48 pm, James Kanze <james.ka...@gmail.comwrote:
On Dec 5, 7:55 am, "subramanian10...@yahoo.com, India"
<subramanian10...@yahoo.comwrote:
* On Dec 4, 8:48 pm, James Kanze <james.ka...@gmail.comwrote:
On Dec 3, 3:21 pm, "subramanian10...@yahoo.com, India"
cout << 5.0 + obj;
The rule is that a member function cannot be called on
a temporary which results from an implicit conversion. (Note
that "my_complex( 5.0 ) + obj" will call the member function.)
The reason for this rule is simple: allowing implicit conversions
here would be too error prone; the programmer expects member
functions to be called on a specific object.
Kindly bear with me for asking the same question regarding 5.0 + obj.
I still am not able to understand the rule that a member function
cannot be called on a temporary which results from an implicit
conversion. why implicit conversion here is error-prone. Kindly give
an example.
In the case of 5.0 + obj, assuming a member operator+, it isn't.
In the more general case, it is; you can't write 5.0 +=
someDouble, and you don't want to be able to write 5.0 += obj.
In the case of double, the rules involve lvalue-ness. There's
no way of overloading on lvalue-ness for user defined types,
however, so another solution has been adopted: if you want to
support implicit conversions on the left hand operand, you make
the function global, and if you don't, you make it a member.
The rules allows you to have a choice.

The rule is also very relevant in expressions like a.f(). Here,
f() is a member function, designed to operate on an object. If
a isn't an object on which it can operate, without the rule, it
would operate on a temporary, which almost certainly isn't what
the programmer wanted.

Also, as Victor pointed out, how is the compiler to guess which
classes to look at? I hadn't considered the question before
Victor mentionned it, but I rather think that without something
like this rule, the compiler would not be implementable.
(Obviously, one can't say for sure until the alternative is
precisely specified.)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Dec 6 '07 #10
consider the following:

#include <iostream>

using namespace std;

class Test
{
public:
Test(int arg = 0) : val(arg) { }

Test(const Test &rhs) : val(rhs.val) { }

Test operator+(const Test &rhs) const;

friend Test operator+(const Test &lhs,
const Test &rhs);

private:
int val;
};

Test Test::operator+(const Test &rhs) const
{
cout << "from member operator+" << endl;
return Test(val + rhs.val);
}

Test operator+(const Test &lhs, const Test &rhs)
{
cout << "from friend operator+" << endl;

return Test(lhs.val + rhs.val);
}

int main()
{
Test obj(10);
Test temp(20);
Test result;

result = obj + temp;

return 0;
}

This generates ambiguity for the expression 'obj + temp' because the
Test::operator+() is const. If it is non-const the friend function is
called. 'Test::operator() const' function has 'this' pointer as
pointer to const object. This is mentioned earlier in this thread by
Abhishek Padmanabh.

From this I understand the following: Kindly correct me if my
understanding is wrong:

For the type 'Test', 'const Test &' is implemented by the compiler as
'const Test * const'. So the friend function becomes
operator+(const Test *const lhs,
const Test *const rhs);

'Test::operator+(const Test &rhs) const' is internally implemented by
the compiler as
'Test::operator+(const Test * const this,
const Test *const rhs);

Since the types and number of parameters for the friend function
operator+() and Test::operator+()const member function are the same,
we get ambiguity error.

My doubt here: is the ambiguity generated due to the above internal
implementation of 'const Test &' as 'const Test *const' ? Or the
reasoning for ambiguity is different.

Kindly clarify.

Thanks
V.Subramanian

Dec 6 '07 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

5 posts views Thread by IvD² | last post: by
5 posts views Thread by Gianni Mariani | last post: by
21 posts views Thread by Paul Steckler | last post: by
3 posts views Thread by subramanian100in | last post: by
2 posts views Thread by subramanian100in | last post: by
13 posts views Thread by George2 | last post: by
2 posts views Thread by z1 | last post: by
reply views Thread by Anwar ali | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.