Overloading operator+ in a template class with 2 templates - c++

I have the following templatŠµ:
template <typename T1, typename T2>
class equationSolution {
public:
T1 a, b, c;
float d;
friend ostream& operator<< <T1, T2>(ostream& str, const equationSolution<T1, T2>& ov);
equationSolution<T1,T2>& operator+=(const equationSolution<T1, T2>& ov, const int& value);
equationSolution() : a(0), b(0), c(0) {}
equationSolution(T1 a1, T1 b1, T1 c1) : a(a1), b(b1), c(c1) {
a = a;
b = b;
c = c;
d = pow(b, 2) - 4 * a * c;
}
}
I managed to overload the output
template <typename T1, typename T2>
ostream& operator<<(ostream& str, const equationSolution<T1, T2>& ov)
{
str << "(" << ov.a << "," << ov.b << "," << ov.c << ")";
return str;
}
But with the operator += I have difficulties.
That's what I did:
friend equationSolution<T1, T2>& operator += (const equationSolution<T1, T2>& ov, const int& value) {
ov.a += value;
ov.b += value;
ov.c += value;
return ov;
}
But I have error:
binary "operator + =" has too many parameters

All assignment operator overloads (all of them) must be member functions, and as such they should take only one argument: The right-hand side of the operator.
That is, an expression like
foo += bar;
will be translated as
foo.operator+=(bar);
You declare the operator function as a member function, but using two arguments. Then you define (implement) the function as a non-member friend function, which is not allowed. The error you mention is from the declaration.
What you should do is something like
equationSolution& operator+=(const int& value)
{
// TODO: Implement the actual logic
return *this;
}

Related

Is it possible to streamline a given set of operators to any arbitrary set of classes?

Consider the following set of classes and the relationship of their operators: We can implement them in two distinct ways. The first where the operators are defined within the class, and the latter where they are defined outside of the class...
template<typename T>
struct A {
T value;
T& operator+(const A<T>& other) { return value + other.value; }
// other operators
};
temlate<typename T>
struct B {
T value;
T& operator+(const B<T>& other) { return value + other.value; }
};
// Or...
template<typename T>
struct A {
T value;
};
template<typename T>
T& operator+(const A<T>& lhs, const A<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators
template<typename T>
struct B {
T value;
};
template<typename T>
T& operator+(const B<T>& lhs, const B<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators
Is there any way in C++ where I would be able to make a single class or struct of operators to where I could simply be able to declare or define them within any arbitrary class C without having to write those same operators multiple times for each class? I'm assuming that the operators will have the same behavior and property for each distinct class that defines them considering that they will all follow the same pattern.
For example:
template<typename T, class Obj>
struct my_operators {
// define them here
};
// Then
template<typename T>
struct A {
T value;
my_operators ops;
};
template<typename T>
struct B {
T value;
my_operators ops;
};
Remember I'm restricting this to C++17 as I'm not able to use any C++20 features such as Concepts... If this is possible, what kind of method or construct would I be able to use, what would its structure and proper syntax look like? If this is possible then I'd be able to write the operators once and just reuse them as long as the pattern of the using classes matches without having to write those operators for each and every individual class...
What about using CRTP inheritance?
#include <iostream>
template <typename T>
struct base_op
{
auto operator+ (T const & o) const
{ return static_cast<T&>(*this).value + o.value; }
};
template<typename T>
struct A : public base_op<A<T>>
{ T value; };
template<typename T>
struct B : public base_op<B<T>>
{ T value; };
int main()
{
A<int> a1, a2;
B<long> b1, b2;
a1.value = 1;
a2.value = 2;
std::cout << a1+a2 << std::endl;
b1.value = 3l;
b2.value = 5l;
std::cout << b1+b2 << std::endl;
}
Obviously this works only for template classes with a value member.
For the "outside the class" version, base_op become
template <typename T>
struct base_op
{
friend auto operator+ (T const & t1, T const & t2)
{ return t1.value + t2.value; }
};
-- EDIT --
The OP asks
now I'm struggling to write their equivalent +=, -=, *=, /= operators within this same context... Any suggestions?
It's a little more complicated because they must return a reference to the derived object... I suppose that (for example) operator+=(), inside base_op, could be something as
T & operator+= (T const & o)
{
static_cast<T&>(*this).value += o.value;
return static_cast<T&>(*this);
}
Taking the answer provided by user max66 using CRTP and borrowing the concept of transparent comparators provided by the user SamVarshavchik within the comment section of my answer, I was able to adopt them and came up with this implementation design:
template<class T>
struct single_member_ops {
friend auto operator+(T const & lhs, T const & rhs)
{ return lhs.value + rhs.value; }
friend auto operator-(T const & lhs, T const & rhs)
{ return lhs.value - rhs.value; }
template<typename U>
friend auto operator+(T const& lhs, const U& rhs)
{ return lhs.value + rhs.value; }
template<typename U>
friend auto operator-(T const& lhs, const U& rhs )
{ return lhs.value - rhs.value;}
};
template<typename T>
struct A : public single_member_ops<A<T>>{
T value;
A() = default;
explicit A(T in) : value{in} {}
explicit A(A<T>& in) : value{in.value} {}
auto& operator=(const T& rhs) { return value = rhs; }
};
template<typename T>
struct B : public single_member_ops<B<T>> {
T value;
B() = default;
explicit B(T in) : value{in} {}
explicit B(B<T>& in) : value{in.value} {}
auto& operator=(const T& rhs) { return value = rhs; }
};
int main() {
A<int> a1(4);
A<int> a2;
A<int> a3{0};
a2 = 6;
a3 = a1 + a2;
B<double> b1(3.4);
B<double> b2(4.5);
auto x = a1 + b2;
auto y1 = a2 - b2;
auto y2 = b2 - a1;
return x;
}
You can see that this will compile found within this example on Compiler Explorer.
The additional templated operator allows for different types: A<T> and B<U> to use the operators even if T and U are different for both A and B provided there is a default conversion between T and U. However, the user will have to be aware of truncation, overflow & underflow, and narrowing conversions depending on their choice of T and U.

Scope operator in Operator Overloading

I'm not able to understand the scope operator in Operator overloading. There are examples when they are using it when they don't. When I'm supposed to write T::operator. Can I write just the operator still works fine or is it recommended to use::?
The example:
Prototype examples (for class T)
Inside class definition
T& T::operator +=(const T2& b){}
Can I write it like T& operator +=(const T2& b){}
Or should I always write it like T& T::operator +=(const T2& b){}
The operator += may be declared as a member function or member template of a class or class template and defined either within the class or class template or outside them.
If it is defined outside the class then the scope operator is required.
The operator may be also declared and defined as a stand-alone non-class function
Consider the following demonstrative program
#include <iostream>
struct A
{
int x = 0;
A & operator +=( char c )
{
x += c;
return *this;
}
};
struct B
{
int x = 0;
B & operator +=( char c );
};
B & B::operator +=( char c )
{
x += c;
return *this;
}
struct C
{
int x = 0;
};
C & operator +=( C & cls, char c )
{
cls.x += c;
return cls;
}
int main()
{
A a;
a += 'A';
std::cout << "a.x = " << a.x << '\n';
B b;
b += 'B';
std::cout << "b.x = " << b.x << '\n';
C c;
c += 'C';
std::cout << "c.x = " << c.x << '\n';
return 0;
}
Its output is
a.x = 65
b.x = 66
c.x = 67
The operator can be also declared as a template operator. For example
#include <iostream>
template <class T>
struct A
{
T x = T();
};
template <class T1, class T2>
T1 & operator +=( T1 &a, const T2 &x ) /* C++ 17 only requires requires( T1 t ) { t.x; }*/
{
a.x += x;
return a;
}
int main()
{
A<int> a;
std::cout << ( a += 10u ).x << '\n';
}
Again if the operator is a member function template and is defined outside its class then the scope resolution operator is required.
#include <iostream>
template <class T1>
struct A
{
T1 x = T1();
template <class T2>
A<T1> & operator +=( const T2 &x );
};
template <class T1>
template <class T2>
A<T1> & A<T1>::operator +=( const T2 &x )
{
this->x += x;
return *this;
}
int main()
{
A<int> a;
std::cout << ( a += 10u ).x << '\n';
}
Inside the class, you don't use the scope resolution operator :::
class T {
public:
// ...
T operator+=(const T2& b)
{
// ...
}
};
If you define the operator outside the class, then you use the scope resolution operator :: in the out of class definition. You still omit it in the declaration:
class T {
public:
// ...
T operator+=(const T2& b);
};
// in the implementation
T T::operator+=(const T2& b)
{
// ...
}
This has nothing to do with recommendation or good practice. Everything stated here is the only way that can work, the other ways are just not correct C++ code.

Operator Overloading with template

I am trying to modify the Add function to represent operator overloading.
#include <iostream>
using namespace std;
template <class T>
class cpair
{
public:
cpair(T x = 0, T y = 0) { A = x; B = y; }
void print()
{
cout << A << " " << B << endl;
}
T A, B;
};
template <class T>
void Add(cpair<T> A1, cpair<T> A2, cpair<T> &R)
{
R.A = A1.A + A2.A;
R.B = A1.B + A2.B;
}
int main()
{
cpair<int> A1(4, 5), A2(1, 3), result;
Add(A1, A2, result);
result.print();
return 0;
}
I am learning operator overloading, but I don't think I have implemented it correctly. The error I get is:
'operator= must be a member function'.
template <class T>
void operator=(const cpair<T> &A1, cpair<T> &A2, cpair<T> &R) {
R.A = A1.A + A2.A;
R.B = A1.B + A2.B;
}
int main()
{
cpair<int> A1(4, 5), A2(1, 3), result;
operator(A1, A2, result);
result.print();
}
How do you go about modifying the Add function to represent operator overloading and then call the function in Main? Thank you.
You're misunderstanding quite a lot it seems. First of all if you want to overload the addition operator it's the operator+ function you need to overload, not the assignment operator.
To fix this you should do e.g.
template <class T>
cpair<T> operator+(cpair<T> const& a, cpair<T> const& b)
{
return cpair<T>(a.A + b.A, a.B + b.B);
}
Secondly, if you overload an operator you can use it just like you would otherwise use it. For example, with e.g.
int a = 5, b = 7, r;
then you would do
r = a + b;
It's the same with your overloaded operators:
cpair<int> a(4, 5), b(1, 3), result;
result = a + b;
If you want to learn more I suggest you get a few good books to read.
template <class T>
class cpair {
public:
cpair& operator+=( cpair const& o )&{
A+=o.A;
B+=o.B;
return *this;
}
friend cpair operator+( cpair lhs, cpair const& rhs ){
lhs+=rhs;
return lhs;
}
//...
the above is the canonical way to override + on a template class.

Overloading operator for default type in template

How can i overload operator in template class for every type expect- for example int and char.
Point<char> operator+ (Point<char> const& sec){
Point<char> tmp(x+2, y+3);
return tmp;
}
Point<int> operator+ (Point<int> const& sec){
Point<int> tmp(x+sec.x + 1, y+sec.y + 1);
return tmp;
}
Point<T> operator+ (Point<T> const& sec){
return Point<T>(x+sec.x, y+sec.y);
}
Something like this doesn't work. I can overload for specific types OR for T, but can't combine both.
You can explicitly specialize outside the class, like so (minimal example):
#include <iostream>
template<class T>
struct Point
{
Point operator+(Point rhs)
{
std::cout << "Generic\n";
return rhs;
}
};
template<>
Point<char> Point<char>::operator+(Point<char> rhs)
{
std::cout << "char\n";
return rhs;
}
template<>
Point<int> Point<int>::operator+(Point<int> rhs)
{
std::cout << "int\n";
return rhs;
}
int main()
{
Point<double> p;
Point<int> i;
Point<char> c;
p + p;
i + i;
c + c;
}
Live on Coliru
You can add an if statement like
if(std::is_same<T, int>::value) {...}
else if(std::is_same<T, char>::value) {...}
else {...}
Write this inside the code for Point operator+(){}.
I have never implemented this, but I think you can make it work.
I don't know if an operator can be overloaded the way you want, but you can try this.
To explicitly specialize a member you need its surrounding class template to be explicitly specialized as well. In your case you can use friends:
template <class T>
class Point {
public:
Point(T x, T y) : x(x), y(y) {}
private:
T x, y;
friend Point<char> operator+ (Point<char> const& a, Point<char> const& b);
friend Point<int> operator+ (Point<int> const& a, Point<int> const& b);
template<class T>
friend Point<T> operator+ (Point<T> const& a, Point<T> const& b);
template<class T>
friend Point<T*> operator+ (Point<T*> const& a, Point<T*> const& b);
};
Point<char> operator+ (Point<char> const& a, Point<char> const& b) {
std::cout << "overload for char" << std::endl;
return a;
}
Point<int> operator+ (Point<int> const& a, Point<int> const& b) {
std::cout << "overload for int" << std::endl;
return a;
}
template <class T>
Point<T> operator+ (Point<T> const& a, Point<T> const&) {
std::cout << "overload for other non-pointers type" << std::endl;
return a;
}
// you can even provide overload for pointers
template <class T>
Point<T*> operator+ (Point<T*> const& a, Point<T*> const&) {
std::cout << "overload for pointers" << std::endl;
return a;
}
int main() {
Point<int> p1(1,1);
p1 + p1;
Point<char> p2(1, 1);
p2 + p2;
Point<long long> p3(1, 1);
p3 + p3;
int i[2];
Point<int*> p4(i, i+1);
p4 + p4;
return 0;
}
overload for int
overload for char
overload for other non-pointer types
overload for pointers

Friend operator behavior (const vs non-const)

I have the following C++ code:
#include <iostream>
template <class T>
void assign(T& t1, T& t2) {
std::cout << "First method" << std::endl;
t1 = t2;
}
template <class T>
void assign(T& t1, const T& t2) {
std::cout << "Second method" << std::endl;
t1 = t2;
}
class A {
public:
A(int a) : _a(a) {};
private:
int _a;
friend A operator+(const A& l, const A& r);
};
A operator+(const A& l, const A& r) {
return A(l._a + r._a);
}
int main() {
A a = 1;
const A b = 2;
assign(a, a);
assign(a, b);
assign(a, a+b);
}
The output is:
First method
Second method
Second method
The output stays the same even if I comment out the the first 2 assigns in the main function.
Can someone please explain to me why the operator+ returns a const A?
The output is the same in both Linux Debian 64bit and Windows 7 64 bit.
It doesn't return a const A at all. It returns a temporary A, which may only bind to a const reference.