473,240 Members | 1,600 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,240 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 2175
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: IvD² | last post by:
During a project I ran into trouble when using multiple inheritance. I was able to resolve the problem, but was unable to really understand the reasons for the error. Here is a short example of...
5
by: Gianni Mariani | last post by:
Can anyone enligten me why I get the "ambiguous overload" error from the code below: friendop.cpp: In function `int main()': friendop.cpp:36: ambiguous overload for `std::basic_ostream<char,...
21
by: Paul Steckler | last post by:
Here's some code that's giving me differing results, depending on the compiler. typedef foo { int A,B; } FOO; int main() {
0
by: ciaran.mchale | last post by:
I used Google to find information about JAXB 2.0 and I ended up downloading a document called "The Java Architecture for XML Binding (JAXB) 2.0: Proposed Final Draft September 30, 2005". ...
3
by: subramanian100in | last post by:
I have tried the following in VC++ 2005 Express Edition and g++ in Linux. Consider the class class my_complex { public: my_complex(double r, double i = 10.0) : re(r), im(i) { }...
2
by: subramanian100in | last post by:
Consider the program #include <iostream> using namespace std; void fn(const char * str, char x = 'Y') { cout << "from fn(const char *, char) - " << str << endl; return;
13
by: George2 | last post by:
Hello everyone, I think compiler is too strict in this case. You can see, no data member, no virtual function. I am using Visual Studio 2008. The compiler error is simply because of Diamond...
4
by: abendstund | last post by:
Hi, I have the following code and trouble with ambiguity due to operator overloading.. The code is also at http://paste.nn-d.de/441 snip>>
2
by: z1 | last post by:
hi - There's one exception: if you have two template rules that match the same "event" (i.e. the same node in the source document), it's technically an error, but the processor can resolve the...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...

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.