# Thread: Using arithmetic overloaded operators with built in types and objects

1. ## Using arithmetic overloaded operators with built in types and objects

Hello it's me again, I would like to know why do we have to use built in type of data as the driving operand in front of the + operator or any overloaded operator.
For example this code doesn't compile, since in the main function double is right from the operator +

Code:
```#include <iostream>
using namespace std;

class Transaction
{
friend double operator+(double, Transaction);
private:
int idNum;
double payment;
public:
Transaction(double , int);
};
Transaction::Transaction(int id, double payment)
{
this->payment = payment;
idNum = id;
}
double operator+(Transaction trans, double payment)
{
double sum;
sum = payment + trans.payment;
return sum;
}
int main(void)
{
Transaction transOne(15, 12.6);
double sum = transOne + 5.2;
cout << sum;
return 0;
}```
yet, If I put 5.2 left from the operator +, code executes correctly.

Code:
```#include <iostream>
using namespace std;

class Transaction
{
friend double operator+(double, Transaction);
private:
int idNum;
double payment;
public:
Transaction(double , int);
};
Transaction::Transaction(int id, double payment)
{
this->payment = payment;
idNum = id;
}
double operator+(Transaction trans, double payment)
{
double sum;
sum = payment + trans.payment;
return sum;
}
int main(void)
{
Transaction transOne(15, 12.6);
double sum = transOne + 5.2;
cout << sum;
return 0;
}```

2. It looks like your function signatures don't match.

3. Originally Posted by MutantJohn
It looks like your function signatures don't match.
Could you please be more precise?

4. Oh, I simply meant that your friend function declaration and the function definition have different argument orders.

Also, there's no need to use a friend function. You can just overload the operator in the class as well.

Code:
```// Example program
#include <cassert>
#include <iostream>

struct point
{
float x;
float y;
float z;

auto operator+(float const n) const -> point
{
return {x + n, y + n, z + n};
}

auto operator==(point const& other) const -> bool
{
return x == other.x && y == other.y && z == other.z;
}
};

int main(void)
{
assert((point{0, 1, 2} + 3 == point{3, 4, 5}));
std::cout << "Tests passed!\n";
return 0;
}```

• Originally Posted by MutantJohn
Oh, I simply meant that your friend function declaration and the function definition have different argument orders.
Originally Posted by MutantJohn

Also, there's no need to use a friend function. You can just overload the operator in the class as well.

Code:
```// Example program
#include <cassert>
#include <iostream>

struct point
{
float x;
float y;
float z;

auto operator+(float const n) const -> point
{
return {x + n, y + n, z + n};
}

auto operator==(point const& other) const -> bool
{
return x == other.x && y == other.y && z == other.z;
}
};

int main(void)
{
assert((point{0, 1, 2} + 3 == point{3, 4, 5}));
std::cout << "Tests passed!\n";
return 0;
}```
I haven't yet used casert library, I am learning by this book
https://hienngong.files.wordpress.co...th_edition.pdf
and I am currently on the Chapter 09. So I really don't know what these functions do (assert, auto).

5. I'm using C++11 and on syntax.

`auto` tells the compiler that it should expected a "trailing return type". I prefer this syntax.

`assert` is a function that checks a boolean condition. If it's true, it's all good. Otherwise, it crashes your code.

And in my `operator+` function, I'm using another short-hand syntax by just returning an initializer list (I'm 90% confident the compiler treats that return statement as a list).

6. If you just want to be able to put the transaction on the left or right of operator + you can certainly do that, you just need to take the time to write it. A nice way of doing it is like this:
Code:
```/* public */ double Transaction::Amount() const
{
return payment_;
}

/* public */ void Transaction::operator+= (double payment)
{
payment_ += payment;
}

// This is a non-member, non-friend implementation of operator+ and as such,
// Transaction:: in the function signature would be wrong.
Transaction operator + (const Transaction& lhs, double amt)
{
Transaction dupe(lhs);
dupe += amt;
return dupe;
}

Transaction operator + (double amt, const Transaction& rhs)
{
return rhs + amt;
}

int main()
{
Transaction transOne(15, 12.60);
transOne = 5.20 + transOne;
cout << transOne.Amount() << endl;
}```
Notice that the bulk of the work is done by operator +=, so if you ever change how you add to transactions, you need to change operator +=, and possibly Transaction operator + (const Transaction& lhs, double amt) as well, but that should be it.

Creating function prototypes for both versions of operator+ would allow you to define them in any order as well, as long as one is written in terms of the other.

7. @MutantJohn:
`auto` tells the compiler that it should expected a "trailing return type". I prefer this syntax.
auto tells the compiler that it should deduce the return type. It's obvious to "deduce" if you provide it directly by using the trailing return type syntax as you did - but the two are separate as auto can be used without the trailing return type syntax.

Not in your example, though, because...
(I'm 90% confident the compiler treats that return statement as a list)
...you return an initializer list, and thus the compiler needs some way of knowing what type of object to initialize using it. Again, you provide that type directly in the trailing return type syntax.

I see little value in using auto in this instance if you still have to use the type name anyway, as is the case with operator+ here... I mean, each to his own, styles differ and such. I prefer the self-documenting nature of explicit return type when it comes to functions/methods, but having it by means of trailing syntax and auto in front... I guess it comes down as to which you prefer to read.

8. You know, I've never actually had much luck when trying to get deduced return types so the "auto" syntax is more naturally associated with trailing return syntax.

I actually opted for trailing style and use it everywhere solely for the sake of consistency. One thing I like is that it hides longer return types a lot better and all your functions align if you have headers and source files. The fact that we can return that in class methods is really cool too! It's a super light and bare syntax. I think it's groovy.

9. Originally Posted by MutantJohn
`assert` is a function that checks a boolean condition. If it's true, it's all good. Otherwise, it crashes your code.
No, it raises an "assertion."

And in my `operator+` function, I'm using another short-hand syntax by just returning an initializer list (I'm 90% confident the compiler treats that return statement as a list).
The compiler deduces it to an initializer list, but the standard says it can implicitly convert an initializer list to whatever object you're returning by passing those parameters in the initializer list directly to the constructor, or in case of a "simple struct type", it initializes it using an aggregate initializer list, I think. Not sure about the standards terminology here. It's hard.

Originally Posted by Xupicor
auto tells the compiler that it should deduce the return type. It's obvious to "deduce" if you provide it directly by using the trailing return type syntax as you did
No, mutantjohn is right in this case. "auto" used in this way tells the compiler to expect a trailing return type.

This originally came from lambdas:

Code:
`[capture list](argument list) -> return type { function body }`
The return type of lambdas is specified by "-> return type" after the function name as opposed to before the function name for normal functions, so the committee then thought, that for consistency's sake, they should do the same for functions, as well. But they couldn't just omit the return type as that would result in a parse error. Hence, they introduced "auto" as a way to tell the compiler "hey, the return type comes later."

but the two are separate as auto can be used without the trailing return type syntax.
And this was introduced in C++14. If you use auto and omit the trailing return type, you're telling the compiler "hey, deduce the return type for me."

So, to clarify:
MyReturnType MyFunction(...) (C++98)

auto MyFunction(...) -> MyReturnType (C++11 and forward)
Tells the compiler the return type comes AFTER the function name. Omitting the return type is an error. This is supported in C++14 and forward too, of course.

auto MyFunction(...) (C++14 and forward)
The return type is deduced based on what you return. If the compiler can't figure it out, it's a compile error.

As for return type before or after function name, it's a matter of style. The obvious improvement of putting it after is that it's easier to spot the function name as opposed to its return type.

10. I should have probably included a little backstory like you did, and specify I'm talking about the newest revision. So, for completeness sake, lets see how the standard changed when it comes to the "new" auto:

C++98 had auto keyword work as storage class specifier (no longer valid usage since C++11), so that doesn't interest us.

From C++11 draft N3242:
7.1.6.4 auto speciﬁer [dcl.spec.auto]
1 The auto type-speciﬁer signiﬁes that the type of a variable being declared shall be deduced from its initializer or that a function declarator shall include a trailing-return-type.
2 The auto type-speciﬁer may appear with a function declarator with a trailing-return-type (8.3.5) in any context where such a declarator is valid.
From C++14 draft N3797:
7.1.6.4 auto speciﬁer [dcl.spec.auto]
1 The auto and decltype(auto) type-speciﬁers designate a placeholder type that will be replaced later, either by deduction from an initializer or by explicit speciﬁcation with a trailing-return-type. The auto type-speciﬁer is also used to signify that a lambda is a generic lambda.
2 The placeholder type can appear with a function declarator in the decl-speciﬁer-seq, type-speciﬁer-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type (8.3.5), that speciﬁes the declared return type of the function.
If the declared return type of the function contains a placeholder type, the return type of the function is deduced from return statements in the body of the function, if any.
From C++17 draft N4582:
7.1.6.4 auto speciﬁer [dcl.spec.auto]1 The auto and decltype(auto) type-speciﬁers are used to designate a placeholder type that will be replaced later by deduction from an initializer. The auto type-speciﬁer is also used to introduce a function type having a trailing-return-type or to signify that a lambda is a generic lambda.
2 The placeholder type can appear with a function declarator in the decl-speciﬁer-seq, type-speciﬁer-seq, conversion-function-id, or trailing-return-type, in any context where such a declarator is valid. If the function declarator includes a trailing-return-type (8.3.5), that trailing-return-type speciﬁes the declared return type of the function. Otherwise, the function declarator shall declare a function.
If the declared return type of the function contains a placeholder type, the return type of the function is deduced from return statements in the body of the function, if any.
The compiler deduces it to an initializer list, but the standard says it can implicitly convert an initializer list to whatever object you're returning by passing those parameters in the initializer list directly to the constructor, or in case of a "simple struct type", it initializes it using an aggregate initializer list, I think. Not sure about the standards terminology here. It's hard.
Well, I'd say, correcting my wording in light of your input and of what the standard actually says, that the return type here isn't as much deduced as it is actually already known, since it was provided explicitly in the trailing-return-type. So the value returned from the function using the return statement - an initializer list in this case - if it's not already of the type needed (and it isn't) is going to go through the process of finding a proper conversion or in other words the compiler will try to initialize a new object of already known type point using returned value as the initializer, so more or less just like you said. Since in our case the type point is an aggregate, it can be initialized by an initializer list as per the usual rules. Again, pretty much exactly like you said.

From C++14 draft N3797:
8.5.1 Aggregates [dcl.init.aggr]
1 An aggregate is an array or a class (Clause 9) with no user-provided constructors (12.1), no private or protected non-static data members (Clause 11), no base classes (Clause 10), and no virtual functions (10.3).
2 When an aggregate is initialized by an initializer list, as speciﬁed in 8.5.4, the elements of the initializer list are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each member is copy-initialized from the corresponding initializer-clause.
8.5 Initializers whole is kind of relevant, especially 8.5.4 List-initialization, 12.3 Conversions is a little further, also relevant. Anyone interested can get the nitty gritty there.

So, holy mother of formal writing, did I just hijack the thread? Well, whiteflags answered the direct question, so I guess it's not that bad, still sorry about that. I'm just a little hungover (talk about understatements), so you'll have to excuse me if I end my ISO trips on the above. I know, you're sooo disappointed. Sorry again!

Oh, and ZeroesAndOnes, don't mind the rambling about technicalities that aren't even connected to your question. If you still have questions about your original problem - don't be afraid to ask them. ; )

11. Sorry if the syntax was "jarring". It's a very JavaScript-y kind of syntax, imo. But I like it. C++11 and onwards has a really nice and new syntax that I think sort of revitalizes C++.

12. I dunno if I would call it a revitalization to put the return type at the end of the signature. Well, I prefer a discussion like this as opposed to you just writing as you like, and leaving us to figure out it's a C++14 feature. While I certainly understand the rationale of "lambdas do this, so everything function-like should do this," preferring it seems... against convention...? I'm not sold on it, I guess is what I'm saying; least of all for reasons like everything will be nicely aligned. I don't care.

And as far as deducing the type all the time... well, have you ever seen If Google was a guy, and got to the part where the black dude asks pseudo questions to the search bar? In some contexts, type deduction is nice, and unavoidable, but if we use it constantly, I start to humanize the compiler. And we're treating the compiler like we treat Google guy.