Why this doesn't compile

L

lali.cpp

Hi,

Sorry for the stupid subject(i could not think of anything better).

Why is the following code not compilable:
class Example
{
public:
// friend Example operator+(const Example&,const Example&);

Example()
{
}
Example(int n):m(n)
{
}

Example operator+(const Example& ex) const
{
cout<<"\nClasss overload called"<<endl;
return Example(m+ex.m);
}
private:
int m;
};
/*Example operator+(const Example& ex1,const Example& ex2)
{
return Example(ex1.m+ex2.m);
}*/
int main()
{
Example ex1;
Example ex2=1+ex1;
return 0;
}

What i expect is that 1+ex1 should actually be interpreted as Example
(1)+ex1(the 1 argument constructor is not explicit) and then the
operator+ function for the temporary object(i.e Example(1)) should be
called.

May be there is some rule regarding temporary objects that i am
missing. Kindly elaborate why is it illegal ?



Regards
Kartik Mahajan
 
M

Michael DOUBEZ

lali.cpp said:
Sorry for the stupid subject(i could not think of anything better).

Why is the following code not compilable:

Because the compiler cannot match operator+(int,const Example&).
The only operator available is Example::eek:perator+(const Example&); it
will work for ex+1 but not 1+ex.

To solve that, drop the member function and use only the friend one and
it will work.
class Example
{
public:

friend Example operator+(const Example&,const Example&);
Example()
{
}
Example(int n):m(n)
{
}

//remove operator+() member function
private:
int m;
};

Example operator+(const Example& ex1,const Example& ex2)
{
return Example(ex1.m+ex2.m); }
int main()
{
Example ex1;
Example ex2=1+ex1;
return 0;
}


What i expect is that 1+ex1 should actually be interpreted as Example
(1)+ex1(the 1 argument constructor is not explicit) and then the
operator+ function for the temporary object(i.e Example(1)) should be
called.

May be there is some rule regarding temporary objects that i am
missing. Kindly elaborate why is it illegal ?

A member function will only be considered with an object of the class
(fortunately or it would be a mess).
 
P

pauldepstein

Because the compiler cannot match operator+(int,const Example&).
The only operator available is Example::eek:perator+(const Example&); it
will work for ex+1 but not 1+ex.

To solve that, drop the member function and use only the friend one and
it will work.


friend Example operator+(const Example&,const Example&);




//remove operator+() member function


Example operator+(const Example& ex1,const Example& ex2)





A member function will only be considered with an object of the class
(fortunately or it would be a mess).

My opinion is different. I think that Example ex2=1+ex1; is
ambiguous because there is no indication of which of the two versions
of operator + to use.

I agree with the OP that 1 just means Example(1) so I don't
understand the respondent who said that the compiler failed to match
operator+(int,const Example&)

These are my current thoughts. It's quite possible that I'm missing
something and that Michael is right.

Just a different opinion.

Paul Epstein
 
P

pauldepstein

My opinion is different.  I think that     Example ex2=1+ex1;    is
ambiguous because there is no indication of which of the two versions
of operator + to use.

I agree with the OP that 1 just means Example(1)  so I don't
understand the respondent who said that the compiler failed to match
operator+(int,const Example&)

These are my current thoughts.  It's quite possible that I'm missing
something and that Michael is right.

Just a different opinion.

Paul Epstein

To clarify. Two different versions of + have actually been declared
(the OP might not realise this).
The friend declaration is a non-member verrsion of operator + and
then there is another member version defined.

These two declarations of + make the use of + ambiguous.

Paul Epstein
 
M

Michael DOUBEZ

Is that what your compiler told you ? The fact is that
Example::eek:perator+() is never considered in the expression 1+ex.

He defined no such overload, it was operator+(const Example&,const
Example&).
If he had defined it, it wouldn't be ambiguous; the compiler could stop
to it and not consider further possible match.

It is not a matter of opinion, please refer to §13.3 in the C++ standard.
To clarify. Two different versions of + have actually been declared
(the OP might not realise this).
The friend declaration is a non-member verrsion of operator + and
then there is another member version defined.

These two declarations of + make the use of + ambiguous.

Only in the case ex1+ex2.
 
P

pauldepstein

Is that what your compiler told you ? The fact is that
Example::eek:perator+() is never considered in the expression 1+ex.




He defined no such overload, it was operator+(const Example&,const
Example&).
If he had defined it, it wouldn't be ambiguous; the compiler could stop
to it and not consider further possible match.


It is not a matter of opinion, please refer to §13.3 in the C++ standard.



Only in the case ex1+ex2.

I never said it was a "matter of opinion". Two people might do a
computation and get different answers; one person might get the right
answer, and the other person might get the wrong answer. They then
could be said to have different opinions on the answer. That is the
sense in which I used the word "opinion."

I did say "it's quite possible that ... Michael is right."

But that's aside from the technical c++ issues -- I will look over
those issues more closely.

Ok, just reread your answer. It appears that the 1 in 1 + ex does
not refer to the object Example(1). For non-explicit constructors,
when is 1 converted into Example(1) and when not?

[Perhaps you're going to refer me to 13.3 of the c++ standard.]

Paul Epstein
 
P

pauldepstein

Because the compiler cannot match operator+(int,const Example&).
The only operator available is Example::eek:perator+(const Example&); it
will work for ex+1 but not 1+ex.

To solve that, drop the member function and use only the friend one and
it will work.


friend Example operator+(const Example&,const Example&);




//remove operator+() member function


Example operator+(const Example& ex1,const Example& ex2)





A member function will only be considered with an object of the class
(fortunately or it would be a mess).

Ok. This is the point that both I and the OP didn't know -- I pasted
it from a c++ website.

"Recall that when an operator is implemented as a member function,
implicit conversions are only performed on the right operand."

I find this rule weird and counter-intuitive.

If there was an overload of the form Example::eek:perator+(int,const
Example&) the code would be unambiguous because the friend function
would require a conversion and the overload wouldn't so the overload
would be implemented.

Paul Epstein
 
M

Michael DOUBEZ

Because the compiler cannot match operator+(int,const Example&).
The only operator available is Example::eek:perator+(const Example&); it
will work for ex+1 but not 1+ex.

To solve that, drop the member function and use only the friend one and
it will work.

friend Example operator+(const Example&,const Example&);



//remove operator+() member function

Example operator+(const Example& ex1,const Example& ex2)



A member function will only be considered with an object of the class
(fortunately or it would be a mess).
[snip]
Ok. This is the point that both I and the OP didn't know -- I pasted
it from a c++ website.

"Recall that when an operator is implemented as a member function,
implicit conversions are only performed on the right operand."

I find this rule weird and counter-intuitive.

It is because the phrasing is misleading.

* An operator can be implemented as a member function (as in the
uncommented version of the OP).
Example Example::eek:perator+(const Example&);
That way, the expression ex1+ex2 can be rewritten as ex1.operator+(ex2).

It is logique that 1+ex2 cannot expand to 1.operator+(ex2) because 1 is
not an object. It would be error prone to let the compiler choose a
conversion from '1': Example(1).operator+(ex2) or Evil(1).operator+(ex2).

* An operator can be expressed as a free function (as in the commented
version of the OP).
Example operator+(const Example&,const Example&);
The expression ex1+ex2 is rewritten to operator+(ex1,ex2).

In this case with 1+ex, the compiler is allowed to construct a temporary
object in order to match operator+(const Ex&,const Ex&) unless there is
an ambiguity and the normal overloading matching rule applies.

It is not that "implicit conversions are only performed on the right
operand", it is that if you use the member function, the left hand side
entity must be the relevant object.
If there was an overload of the form Example::eek:perator+(int,const
Example&) the code would be unambiguous because the friend function
would require a conversion and the overload wouldn't so the overload
would be implemented.

I don't understand your point here. I can legally declare all three
overload:
Example operator+(const Example&,const Example&);
Example operator+(int,const Example&);
Example operator+(const Example&,int);

There is no ambiguity, the version with 'int' will be chosen first with
1+ex or ex+1.
 

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,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top