Template class with operator overload - c++

Here is my question about template class
aclass<int> A{1,2};
aclass<float> B{3.0,4.0};
aclass<int> C;
int main()
{
C=A+B; //How to overload this operator in a simple way?
B=A; //And also this?
return 0;
}
How can I overload operator to handle template class with different types?
(Sorry for my poor English)

You can have member function templates inside your class template:
template <typename T>
struct aclass
{
aclass(aclass const &) = default;
aclass & operator=(const aclass &) = default;
template <typename U>
aclass(aclass<U> const & rhs) : a_(rhs.a_), b_(rhs.b_) {}
template <typename U>
aclass & operator=(aclass<U> const & rhs)
{
a_ = rhs.a_;
b_ = rhs.b_;
return *this;
}
T a_, b_;
};

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.

Inherit operators defined outside class

In this minimal example I have a class A with an operator + defined outsise of it:
template<class T> class A {};
template<class T1, class T2> void operator+(A<T1> a, A<T2> b) {}
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
I've tried to create an implicit conversion from B to A but it requires the operator+ to be a friend of A and be defined inside A which will cause problems when more than one instance of A<...> gets instantiated.
So, is there any other way to do this without having to define the operator+ again?
Thank you in advance for any help.
template<class T> class A {
template<class T2>
friend void operator+(A const& lhs, A<T2> const& rhs) {}
};
template<class T> class B : public A<T> {};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
this works. The assymetry in + (one template, one not) ensure that multiple As don't conflict with their +.
In some situations you really need lhs to be an instance of B:
template<class T> struct A {
template<class D, class T2, std::enable_if_t<std::is_base_of<A, D>{}, bool> =true >
friend void operator+(D const& lhs, A<T2> const& rhs) {
std::cout << D::name() << "\n";
}
static std::string name() { return "A"; }
};
template<class T> struct B : public A<T> {
static std::string name() { return "B"; }
};
int main(int, char**) {
B<int> a, b;
a + b;
return 0;
}
which uses A's operator+, but the LHS is of type B. Doing this for B<T2> on the right hand side isn't very viable, it gets ridiculous.

Friend specific template instantiation of operator

I have a class template and an operator template that needs to access its private field. I can make a template friend:
template <typename T>
class A {
int x;
template <typename U>
friend bool operator==(const A<U>& a, const A<U>& b);
};
template <typename T>
bool operator== (const A<T>& a, const A<T>& b) {
return a.x == b.x;
}
int main() {
A<int> x, y;
x == y;
return 0;
}
But is it possible to make only operator==<T> friend for A<T> and not making operator==<int> friend of A<double> ?
If having trouble with friend, then bring the declaration forward, before the A class is defined.
template <typename T>
bool operator== (const A<T>& a, const A<T>& b);
Then you can friend it more clearly. Full solution (ideone):
template <typename T>
class A;
// declare operator== early (requires that A be introduced above)
template <typename T>
bool operator== (const A<T>& a, const A<T>& b);
// define A
template <typename T>
class A {
int x;
// friend the <T> instantiation
friend bool operator==<T>(const A<T>& a, const A<T>& b);
};
// define operator==
template <typename T>
bool operator== (const A<T>& a, const A<T>& b) {
return a.x == b.x;
}
Yes you can. The syntax is as follows:
template <typename T>
class A {
int x;
friend bool operator==<>(const A& a, const A& b);
};
And put your operator== definition(or just a declaration) before the A class.

C++: Making a template operator= overload a friend

So I have a templated vektor class
template<t>
class vektor
{
...
}
and I want to be able to write
vektor<int> x;
vektor<float> y;
...
y = x;
so I modify the class
template<t>
class vektor
{
template<typename U>
vektor<T>& operator=(const vektor<U> &r) {
....
}
...
}
And I'd like this function to be friend with r; that is, I want to be able to access the private members of r. Since operator= is special I can't overload operator= as a non-member function and friend it as I might normally do and friend declarations of say
template<typename U> friend vektor<U>& operator=(const vektor<T> &r);
also return "must be a nonstatic member function"
Is there a way to confer friendship in this example?
There are two quick solutions for this problem (both of them are not ideal).
Suppose that the class with very interesting name vektor looks like this (it is only an example which should illustrate the following code):
template<typename T>
class vektor
{
T data;
public:
vektor(T otherData) :
data(otherData)
{
}
T GetData() const
{
return data;
}
// ...
};
Both of solutions can be tested on the following example of code:
vektor<int> x(1);
vektor<float> y(2.0f);
y = x;
std::cout << "x.data = " << x.GetData() << std::endl;
std::cout << "y.data = " << y.GetData() << std::endl;
First solution: auxiliary friend function template
In this solution an auxiliary friend function Copy is used to execute all copy operations and is called from copy assignment operator:
template<typename T>
class vektor
{
// ...
public:
// ...
template<typename U>
vektor<T>& operator=(const vektor<U>& r)
{
return Copy(*this, r);
}
template<typename V, typename U>
friend vektor<V>& Copy(vektor<V>& l, const vektor<U>& r);
};
template<typename V, typename U>
vektor<V>& Copy(vektor<V>& l, const vektor<U>& r)
{
l.data = static_cast<V>(r.data);
return l;
}
Second solution: friend class template
Second solution is to make all vektor class template instantiations friends to each other:
template<typename T>
class vektor
{
// ...
public:
// ...
template<typename U>
vektor<T>& operator=(const vektor<U>& r)
{
data = static_cast<T>(r.data);
return *this;
}
template<typename U>
friend class vektor;
};

C++ -- why we have to define this friend template class

template<class T>
class auto_ptr2 {
public:
explicit auto_ptr2(T *p = 0): pointee(p) {}
template<class U>
auto_ptr2(auto_ptr2<U>& rhs): pointee(rhs.release()) {}
~auto_ptr2() { delete pointee; }
template<class U>
auto_ptr2<T>& operator=(auto_ptr2<U>& rhs)
{
if (this != &rhs) reset(rhs.release());
return *this;
}
T& operator*() const { return *pointee; }
T* operator->() const { return pointee; }
T* get() const { return pointee; }
T* release()
{
T *oldPointee = pointee;
pointee = 0;
return oldPointee;
}
void reset(T *p = 0)
{
if (pointee != p) {
delete pointee;
pointee = p;
}
}
private:
T *pointee;
//template<class U> friend class auto_ptr2<U>;
// Question 1> Why we have to define this friend class
// Question 2> I cannot compile this code with above line with VS2010.
// Error 1 error C3772: 'auto_ptr2<T>' : invalid friend template declaration
};
thank you
Why we have to define this friend class
I'm fairly sure you don't; as far as I can see, nothing is referencing the private member of a different template instantiation. You would need it if the copy constructor or assignment operator manipulated rhs.pointee directly, rather than just calling rhs.release().
I cannot compile this code with above line with VS2010.
The declaration should be:
template<class U> friend class auto_ptr2;