Lk2
Lk2

Reputation: 51

Operator overloading+ to add multiple objects

I need to add multiple objects using operator overloading such as below:

ex1 operator+(const ex1 &c1, const ex1 &c2, more++){
    return ex1(c1 + c2 + more++);
}

This function adds two objects, however I want to add multiple objects. Is that possible?

int main(){
  // first for example I want to add 3 objects
  ex1 ob1, ob2, ob3;
  ob1 + ob2 + ob3;

  code..
  code..

  // and after that I want to add for example 10 or more objects  
  ex1 ob1, ob2, ob3,..., ob10;
  ob1 + ob2 + ob3 +....+ ob10;
}

Upvotes: 2

Views: 4044

Answers (4)

Ziezi
Ziezi

Reputation: 6457

If you want your overloaded operator to work for multiple objects, what you need is chaining*, this could be ensured when you return your result by reference:

ex1& operator+(const ex1 &c1, const ex1 &c2){

    return ex1.var = c1.var + c2.var;
}

or if the operator is a class member:

ex1& operator+(const ex1 &rhs) {

    return ex1.var = this.var + rhs.var; 
}

once you have the above definition, you can add multiple objects as follows:

ex1 + ex2 + ex3

which will be equivalent to:

(ex1 + ex2) + ex3 => sum(ex1,ex2) + ex3 => sum(sum(ex1,ex2), ex3)

i.e. it is always reduced to binary operation between two operands.

To answer your updated question, here is a list of all the operators that could be overloaded, regardless of their arity (unary, binary) or affix (prefix, postfix). In the case of your updated question you are looking for postfix, unary operator overload.

*Multiple method calls, where each method returns an object, allowing the calls to be chained together in a single statement without requiring variables to store the intermediate results

Upvotes: 1

Armen Tsirunyan
Armen Tsirunyan

Reputation: 132984

You need only overload + for two objects. It will then automagically work if you try to add three or more objects, because a + b + c is equivalent to (a+b)+c, or in terms of operator-function calls:

 operator+(operator+(a, b), c)

As long as you return an appropriate type from your + routine, you should be fine.

If you have an array of objects and want to sum all of them up, once again, you only need to overload operator + for two objects and then you can use the std::accumulate function from <numeric> header:

std::vector<ex1> objects = {/*...lots of objects*/};
ex1 sum = std::accumulate(objects.begin(), objects.end(), ex1());

re update: By overloading operators in C++ you can change the return type and semantics of what an operator does, but you cannot change any of the following:

  • the precedence of the operator (i.e. you cannot make a+b*c be equivalent to (a+b)*c
  • the arity of the operator (i.e. you cannot overload a unary operator to take 2 operands and vice versa. You can't for example, make % work liks %a or a%
  • you can't change if the (unary) operator is postfix or prefix, so you can't make the syntax a- or a+ work

So the answer to your second question is no.

Upvotes: 2

David Hammen
David Hammen

Reputation: 33116

With one exception, C++ only has unary operators and binary operators. The one exception is the ternary operator, exemplified by x = condition ? 0 : 42;. With regard to operator+, that is either a unary operator (e.g., +42) or a binary operator (40+2).

You can easily create a custom function that takes three ex1 objects as input and somehow computes the sum of those three objects. However, you cannot call this function operator+. There's no place in C++ for an operator+ that takes three arguments.

There are a number of ways around this restriction. The simplest is to create an overload of binary operator+ that computes the sum of a pair of ex1 objects, creating a new ex1 object as output. The statement ex1 d=a+b+c; will result in two calls to ex1 operator+(const ex1&, const ex1&). Both will create a temporary objects of type ex1. The temporary that represents the value of a+b+c is then passed to ex1::operator= to assign the value of that expression to d.

If you are doing this over and over and over, the creation of those temporary objects might well represent a performance bottleneck. If you are only doing this a few times, that performance bottleneck is a non-issue. The only time you need to worry is if this is an issue, and determining whether that's the case is an issue for you to resolve.

One way of overcoming this performance bottleneck is to create a function (or functions) that take more than two objects as input and creating a sum from those multiple objects. The downside is that you cannot name this function operator+, and hence you cannot use d=a+b+c. You'd instead have to use something like ex1::add_three(ex1&d, const ex1&a, const ex1&b, const ex1&c).

Another approach is to use expression templates as a means for implementing lazy evaluation. Your operator+(const ex1& a, constex1& b) doesn't actually calculate a+b. It instead creates an object that eventually will calculate a+b. The expression a+b+c in turn creates another object that eventually will calculate that result. Finally, the expression d=a+b+c evaluates that expression and assigns it to d, and (if implemented correctly) does so without creating any temporaries.

This approach has also its downsides. Sometimes it is better to create a temporary. The Eigen package does a very good job of determining when its better to create a temporary as opposed to using expression templates that defer calculation.

Upvotes: 0

Adi Levin
Adi Levin

Reputation: 5233

Just define

ex1 operator+(const ex1 &c1, const ex1 &c2){
    return ex1(c1.inner_value + c2.inner_value);
}

And then

a + b + c

Will be interpreted as

operator+(  operator+(a,b) , c )

So it should work

Upvotes: 2

Related Questions