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.
Related
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;
}
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.
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
I have this program with 2 template functions :
#include <iostream>
template <class T> void assign(T& t1,T& t2){
std::cout << "First method";
t1=t2;
}
template <class T> void assign(T& t1,const T& t2) {
std::cout << "Second method";
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+b);
}
i cant understand why does the assign(a,a+b) call the second template function
, in the operator+ we are createing a new A object and call the ctor with an int parameter.
it is creating a+b as const object ?
it is creating a+b as const object ?
No, it is creating a temporary. Temporaries are binded to rvalue references. You can verify that with a 'third' function (a universal reference, in this case)
template <class T>
void assign(T& t1, T&& t2) {
std::cout << "Third method";
t1=t2;
}
As you don't have one, the compiler will pick the const reference overload. Why ?
Suppose you have
void add(int & x)
{
++x;
}
unsigned y = 0;
add(y); // create a temporary to int
std::cout << y << "\n"; // what's the value of y ?
Given a template and a more specialized overload:
template <typename T>
const T& some_func(const T& a, const T& b)
{
std::cout << "Called base template\n";
return (a < b) ? a : b;
}
template <typename T>
T* const& some_func(T* const& a, T* const& b)
{
std::cout << "Called T* overload\n";
return (*a < *b) ? a : b;
}
Then the following works as expected:
int main()
{
std::cout << some_func(5.3, 6.2) << "\n";
double a = 1;
double b = 2;
double *p = &a;
double *q = &b;
const double *ret = some_func(p, q);
std::cout << *ret << "\n";
return 0;
}
With the first printing Called base template, the second printing Called T* overload. If we replace the overload signature with:
template <typename T>
const T*& some_func(const T*& a, const T*& b)
then the second call now calls the base template. Given that int const& x is equivalent to const int& x, am I incorrect in assuming T* const& is equivalent to const T*&? Why is the first version resolved properly while the second is not?
Yes you are incorrect. In const T*& T is const, in T* const& the pointer (T*) is const.
The change happens when you shift const to the right of *. const T*& and T const *& are equivalent but T* const& is different. Typedefs can help, given
typedef T *TPtr;
const TPtr& is equivalent to TPtr const & is equivalent to T* const &.
Declarators in C/C++ are hard to parse (for a human). Even the inventor of C said so.
T const & and const T & are identical; and U const * and const U * are identical.
But S & and T const & are not the same even for T = S. What you have is even worse, namely S = U const * and T = U *.