Operator Overloading on Class Templates

Operator overloading on class templates

// In MyClass.h
MyClass<T>& operator+=(const MyClass<T>& classObj);

// In MyClass.cpp
template <class T>
MyClass<T>& MyClass<T>::operator+=(const MyClass<T>& classObj) {
// ...
return *this;
}

This is invalid for templates. The full source code of the operator must be in all translation units that it is used in. This typically means that the code is inline in the header.

Edit: Technically, according to the Standard, it is possible to export templates, however very few compilers support it. In addition, you CAN also do the above if the template is explicitly instantiated in MyClass.cpp for all types that are T- but in reality, that normally defies the point of a template.

More edit: I read through your code, and it needs some work, for example overloading operator[]. In addition, typically, I would make the dimensions part of the template parameters, allowing for the failure of + or += to be caught at compile-time, and allowing the type to be meaningfully stack allocated. Your exception class also needs to derive from std::exception. However, none of those involve compile-time errors, they're just not great code.

Overloading template operator in derived class

I think the problem here is that a using declaration only brings the declarations of functions and function templates into a derived class that have signatures which are not overridden by members of the derived class [namespace.udecl]/15. So this code should indeed not compile.

Use free functions instead of class members to fix the problem:

#include <type_traits>

class Base
{
public:
template<class T, std::enable_if_t<std::is_scalar_v<T>>* = nullptr>
friend void operator>>(Base&, T& value) {
}
};

class Derived: public Base
{
public:
template<class T, std::enable_if_t<!std::is_scalar_v<T>>* = nullptr>
friend void operator>>(Derived&, T& value) {
}
};

int main()
{
int foo;

Base base;
base >> foo;

Derived derived;
derived >> foo;
}

live example here

Overloaded operator= to switch between template types

When you do the template inheritance, you have to be explicit in case of base classes members. More read:

  • Why do I have to access template base class members through the this pointer?
  • Derived template-class access to base-class member-data
  • Accessing base member functions in class derived from template class

In your case, the members text, and operator=, can be brought via using declaration.

class BuilderGenericList : public BuilderFunctions<BuilderGenericList> 
{
public:
BuilderGenericList() = default;
using BuilderFunctions<BuilderGenericList>::text;
using BuilderFunctions<BuilderGenericList>::operator=;
// ... so on, other members from base if needed!
};

// Build configuration details
class BuilderRootList : public BuilderFunctions<BuilderRootList>
{
public:
BuilderRootList() = default;
using BuilderFunctions<BuilderRootList>::text;
using BuilderFunctions<BuilderRootList>::operator=;
// ... so on, other members from base if needed!
};

Live Demo

Note that, this will make the memberusing BuilderFunctions<BuilderGenericList>::text public, if this is not what wanted, consider the suggestion by @Jarod42 in other answer.

overloading operator ostream for template class in c++ not working

As the error message said, the friend declaration declares a non-template operator<<, but it's defined as a template, they don't match.

You can make the friend declaration referring to the operator template, e.g.

// forward declaration
template<class T = int, unsigned int SIZE =2>
class FixedPoint;

// declaration
template<class T,unsigned int SIZE>
std::ostream& operator<<(std::ostream& os ,const FixedPoint<T,SIZE>& price);

template<class T, unsigned int SIZE>
class FixedPoint {
public:
...
friend std::ostream& operator<< <T, SIZE> (std::ostream& os ,const FixedPoint<T, SIZE>& price);
// or just
// friend std::ostream& operator<< <> (std::ostream& os ,const FixedPoint& price);
...
};

// definition
template<class T,unsigned int SIZE>
inline std::ostream& operator<<(std::ostream& os ,const FixedPoint<T,SIZE>& price){
os << price.dollars << "." << price.cents;
return os;
}

Implementing overloads for and operators in a template class

Turning up the warning level of the compiler helps. By using -Wall with g++, I get the following warnings before the linker error.

socc.cc:13:58: warning: friend declaration ‘std::istream& operator>>(std::istream&, MyClass<MYTYPE>&                    )’ declares a non-template function [-Wnon-template-friend]
friend istream& operator>>(istream&, MyClass<MYTYPE>&);
^
socc.cc:13:58: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
socc.cc:14:57: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyClass<MYTYPE> ’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<<(ostream&, MyClass<MYTYPE>);

You need to use function templates for the operator>> and operator<< functions. You can declare them before the definition of the class with:

// Forward the class template.
template <class MYTYPE> class MyClass;

// Declare the function templates.
template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);

template <class MYTYPE>
std::ostream& operator<<(st::ostream&, MyClass<MYTYPE>);

Then, you'll have to use the friend declaration with the appropriate template parameter.

// This makes sure that operator>><int> is not a friend of MyClass<double>
// Only operator>><double> is a friend of MyClass<double>
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);

Here's an updated version of your code that builds for me. I haven't tried to run it.

#include <iostream>
#include <string>
using namespace std;

template <class MYTYPE> class MyClass;

template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);

template <class MYTYPE>
std::ostream& operator<<(std::ostream&, MyClass<MYTYPE>);

template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {};

friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
};

template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
dim = x;
name = y;
myVector = new MYTYPE[dim];
}

template <class MYTYPE>
std::istream& operator>>(std::istream& X, MyClass<MYTYPE>& a){
cout<<"Reading vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++){
cout<<a.name<<'['<<indice<<"]= ";
X >> a.myVector[indice];
}
return X;
}

template <class MYTYPE>
std::ostream& operator<<(std::ostream& X, MyClass<MYTYPE> a){
X<<"Vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++)
X<<a.myVector[indice]<<' ';
X<<endl;
return X;
}

int main() {
MyClass<int> object(4, "Ints vector");
MyClass<string> object2(5, "String vector");
cin >> object;
cin >> object2;
cout << object;
cout << object2;
system("pause");
return 0;
}


Related Topics



Leave a reply



Submit