grr... this old nut

G

grahamo

I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;


Now I know I can invoke that version of the operator by using
something like;


employee e1, e2;

employee e3 = operator+(e1,e2);


however I know there are other ways to have it invoked...thereby
illustrating its use. What other ways are there? I thought


employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).


any help much appreciated.


cheers

GrahamO
 
J

John Harrison

grahamo said:
I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;


Now I know I can invoke that version of the operator by using
something like;


employee e1, e2;

employee e3 = operator+(e1,e2);


however I know there are other ways to have it invoked...thereby
illustrating its use. What other ways are there? I thought


employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).


any help much appreciated.


cheers

GrahamO

It should work like that. Can you supply a complete program and explain what
happens instead.

john
 
H

Howard

John Harrison said:
It should work like that. Can you supply a complete program and explain what
happens instead.

john

Doesn't the function have to be const in order to chain it like that, since
e1+e2+e3 creates a temporary (or two)?

-Howard
 
P

Peter van Merkerk

grahamo said:
I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;

It would help if you post minimal, yet compilable code that demonstrates
the problem you are having. Do you mean that operator+() is a member
function of the employee class?
In that case it should only have one employee argument:

class employee
{
public:
employee operator+(const employee& e2)
{
// Return the sum of *this and e2...
}
};

You could also declare the operator+() function outside the scope of the
employee class. In that case you do need two employee arguments. Since
only friends can touch your employee's private parts, you may have to
make operator+(const employee& e1, const employee& e2) a friend of employee:

class employee
{
// Only needed if operator+() needs to have access to employees
// privates.
friend employee operator+(const employee& e1, const employee& e2);

// ...other stuff...

};

employee operator+(const employee& e1, const employee& e2)
{
// Return the sum of e1 and e2...
}

Anyway, defining an operator+() for employees seems to be an excellent
example of inappropriate use of operator overloading. To me it is not
obvious what happens if you add two employees. Does it mean that e1 and
e2 have intercourse and produce another employee... in that case the
multiplication operator would be more appropriate ;-)
 
A

Andre Kostur

Doesn't the function have to be const in order to chain it like that,
since e1+e2+e3 creates a temporary (or two)?

It's a freestanding function (it's not a member function, only a friend),
it can't be const.
 
H

Howard

Andre Kostur said:
It's a freestanding function (it's not a member function, only a friend),
it can't be const.

Oops! :) I was thinking of a member function returning a reference. I
realized my mistake immediately, and cancelled my post seconds after sending
it, but I guess it still shows up for some people. Sorry.

-Howard
 
A

Ali Cehreli

I have done this before but it keeps eluding me when I revisit it...

I have a class employee defined with;

friend employee operator+(const employee& e1, const employee& e2) ;

It is better to implement the free operator+ in terms of the member
operator+=, which makes the friendship unnecessary.

[...]
employee e4 = e1+e2+e3;

would do the trick but that doesn't invoke it (using latest G++
compiler).

Here is an example:

class C
{
int i_;

public:

explicit C(int i)
:
i_(i)
{}

C & operator+= (C const & other)
{
i_ += other.i_;
return *this;
}

int value() const
{
return i_;
}
};

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
return result += rhs;
}

#include <iostream>

int main()
{
C const one(1);
C const two(2);
C const three(3);
C const result = one + two + three;

std::cout << result.value() << '\n';
}

Ali
 
H

Howard

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
return result += rhs;
}

Is that legal? I'd think that it might invoke undefined behavior (but I'm
probably wrong. :)) Even if it works, though, I'd prefer to break it into
two lines:

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
result += rhs;
return result;
}

Operator += returns a reference to result, which is then returned as n
object (not a reference), so I guess a copy must be made there (skipping
over possible optimizations, of course). So I guess it's ok, but it just
looks ugly to me, and performs multiple actions on one line (calling the
operator and then returning a copy of that result), something I'm loathe to
do.

-Howard
 
A

Ali Cehreli

Is that legal? I'd think that it might invoke undefined behavior (but
I'm probably wrong. :)) Even if it works, though, I'd prefer to break
it into two lines:

C operator+ (C const & lhs, C const & rhs) {
C result(lhs);
result += rhs;
return result;
}

Operator += returns a reference to result, which is then returned as n
object (not a reference), so I guess a copy must be made there (skipping
over possible optimizations, of course). So I guess it's ok, but it
just looks ugly to me, and performs multiple actions on one line
(calling the operator and then returning a copy of that result),
something I'm loathe to do.

-Howard

It is all legal as you described. Actually I thought at least three times
before posting that code. I would have written what you suggested if I
thought just one more time :)

Ali
 
A

Arijit

Peter van Merkerk said:
grahamo wrote:

<snip>

class employee
{
public:
employee operator+(const employee& e2)
{
// Return the sum of *this and e2...
}
};

You could also declare the operator+() function outside the scope of the
employee class. In that case you do need two employee arguments. Since
only friends can touch your employee's private parts, you may have to
make operator+(const employee& e1, const employee& e2) a friend of employee:

class employee
{
// Only needed if operator+() needs to have access to employees
// privates.
friend employee operator+(const employee& e1, const employee& e2);

// ...other stuff...

};

employee operator+(const employee& e1, const employee& e2)
{
// Return the sum of e1 and e2...
}

Anyway, defining an operator+() for employees seems to be an excellent
example of inappropriate use of operator overloading. To me it is not
obvious what happens if you add two employees. Does it mean that e1 and
e2 have intercourse and produce another employee... in that case the
multiplication operator would be more appropriate ;-)


Shouldn't operator+ return a const object ? I mean

const employee operator+(const employee& e1, const employee& e2)
{
......
}

Otherwise you can write

employee e1,e2,e3;
(e1+e2) = e3;

-Arijit
 
P

Peter van Merkerk

Arijit said:
Shouldn't operator+ return a const object ? I mean

const employee operator+(const employee& e1, const employee& e2)
{
.....
}

Otherwise you can write

employee e1,e2,e3;
(e1+e2) = e3;

I see your point. But even the standard library (e.g. std::string)
doesn't do this, so I guess I'm in good company ;-)

Could someone explain why the standard library does not return const
objects with operator+()?
 
J

JKop

Could someone explain why the standard library does not return const
objects with operator+()?

It's redundant.


Take the following:

int GetNumber();

int main()
{
const int& p = GetNumber();
}

int GetNumber()
{
int k = 42;

--k;

k /= 2;

k = 6 / k;

return k;
}


See how I bound the return value to a const reference, I
had no choice in the matter. What's returned from that
function, and from your operator+, is a "temporary".

What's a temporary? It's a const object that goes out of
scope at the next semicolon. So take the following:

void Blah(const int&);

int main()
{
int p = 42;

Blah(p + 7);
}


What gets passed to Blah? A temporary, it only exists for
as long as it has to, and it can't be edited, it's const.
This particular temporary is destroyed immediately at the
next semicolon, ASAP.


So... return values. They come in two forms:

Type A)

int Blah();
int* Glah();

Here, what's being returned is just a temporary. A
temporary is const, so sticking const in there would be
like calling out "Forename Surname" to your own sister, ie.
it's redundant.


Type B)

int& Blah();

Here, what's being returned is an actual reference to an
object. Here, specifying const will actually make a
difference:

int& AA();
const int& BB();

int main()
{
AA() = 5;

BB() = 6; //Compile ERROR
}


Anyway, without ranting-on too much, all that's being
returned form your Type A functions is a simple temporary,
they're automatically const, so you don't have to specify
it, you don't have a choice either way.

And remember, it's just a temporary!

-JKop
 
J

John Harrison

Here, what's being returned is just a temporary. A
temporary is const, so sticking const in there would be
like calling out "Forename Surname" to your own sister, ie.
it's redundant.

Not that myth again. A temporary is not const, here is the proof

class X
{
public:
void a_non_const_method()
{
x = 1;
}
private:
int x;
};

X func()
{
X
return x;
}

int main()
{
func().a_non_const_method();
}

The correct rule is that a temporary may not be bound to a noo-const
reference, which isn't the same thing at all.

john
 
D

DaKoadMunky

Shouldn't operator+ return a const object ? I mean
const employee operator+(const employee& e1, const employee& e2)
{
.....
}

Otherwise you can write

employee e1,e2,e3;
(e1+e2) = e3;

I have never understood why a return value that is of class type is modifiable
when a return value that is of primitive type is not modifiable.

<CODE>

#include <string>
using std::string;

string ReturnClassType()
{
return "";
}

int ReturnPrimitiveType()
{
return 0;
}

int main()
{
//This is okay!
ReturnClassType() = "";

//This is not okay!
ReturnPrimitiveType() = 0;

return 0;
}

</CODE>

This seems like an inconsistency to me. Both functions return temporary
objects yet one temporary is modifiable and the other temporary is not.

It seems as though one is an l-value and the other is not.

Can anyone help me to understand this?

This was actually discussed months ago and I did not grok the replies I
received. I will look at them again. Until then if anyone can steer me in the
right direction I would appreciate it.
 
J

JKop

Can anyone help me to understand this?


Sure I can, you ain't got a C++ compiler there.

Get yourself a "C++ compiler" and compile it (or attempt to
do so), and then all will become clear.


-JKop
 
J

JKop

JKop posted:
Sure I can, you ain't got a C++ compiler there.

Get yourself a "C++ compiler" and compile it (or attempt to
do so), and then all will become clear.


-JKop


Sorry!

I let my arrogance get ahead of me there.

After having posted that, I realized that it was very likely that you had
tested your code and so I tried to compile it myself, and to my disgust, it
compiled.

Since when can a temporary be an l-value?


-JKop
 
T

tom_usenet

Is that legal? I'd think that it might invoke undefined behavior (but I'm
probably wrong. :)) Even if it works, though, I'd prefer to break it into
two lines:

C operator+ (C const & lhs, C const & rhs)
{
C result(lhs);
result += rhs;
return result;
}

Operator += returns a reference to result, which is then returned as n
object (not a reference), so I guess a copy must be made there (skipping
over possible optimizations, of course). So I guess it's ok, but it just
looks ugly to me, and performs multiple actions on one line (calling the
operator and then returning a copy of that result), something I'm loathe to
do.

The most efficient implementation is actually a bit weird:

C operator+ (C lhs, C const & rhs)
{
lhs += rhs;
return lhs;
}

That is potentially more efficient when a temporary is passed as the
first parameter. e.g.
C() + C();

Tom
 
J

JKop

The most efficient implementation is actually a bit weird:

C operator+ (C lhs, C const & rhs)
{
lhs += rhs;
return lhs;
}

That is potentially more efficient when a temporary is passed as the
first parameter. e.g.
C() + C();


Or maybe even:

C operator+(const C& lhs, const C& rhs)
{
C temp = lhs;

return temp += rhs;
}


-JKop
 
T

tom_usenet

Or maybe even:

C operator+(const C& lhs, const C& rhs)
{
C temp = lhs;

return temp += rhs;
}

Nope, that gets rid of the efficiency gain from passing lhs by value.
Consider:

C aC(C() + c); //c is some value of type c

Your version has (assuming NRVO)
1 default constructor call
1 copy constructor call

My version has (same assumption)
1 default constructor call

IOW, the parameter ends up being constructed right inside the return
value!

Tom
 
J

JKop

tom_usenet posted:
Nope, that gets rid of the efficiency gain from passing lhs by value.
Consider:

C aC(C() + c); //c is some value of type c

Your version has (assuming NRVO)
1 default constructor call
1 copy constructor call

My version has (same assumption)
1 default constructor call

IOW, the parameter ends up being constructed right inside the return
value!

Tom


Okay, I'll get rid of that extra constructor (which
would'be been optimized away in anyway!) with:

C operator+(const C& lhs, const C& rhs)
{
C temp(lhs);

return temp += rhs;
}


Check.


-JKop
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top