"undefined reference to `operator>>(std::istream&, Complex<int>&)" for template Complex<T>

Viewed 186

My code:

#include <iostream>
using std::cin;
using std::cout;
using std::istream;
using std::ostream;

template<typename T>
class Complex
{
    T real, img;
public:
    Complex():real(0), img(0){}
    friend istream& operator>>(istream& input, Complex& c1);
    friend ostream& operator<<(ostream& output, Complex& c1);
    Complex operator+(Complex& c1);
};

template<typename T>
istream& operator>>(istream& input, Complex<T>& c1)
{
    cout<<"Real: ";
    input>>c1.real;
    cout<<"Imag: ";
    input>>c1.img;
    return input;
}

template<typename T>
ostream& operator<<(ostream& output, Complex<T>& c1)
{
    output<<c1.real<<"+"<<c1.img<<"i";
    return output;
}

template<typename T>
Complex<T> Complex<T>::operator+(Complex<T>& c1)
{
    Complex temp;
    temp.real = this->real + c1.real;
    temp.img = this->img + c1.img;
    return temp;
}

int main()
{
    Complex<int> cmp1;
    cin>>cmp1;
    return 0;
}

The error I'm getting is at cin>>cmp1 which is undefined reference to 'operator>>(std::istream&, Complex<int>&)'. But I can't find anything wrong in my code.

The code works if I make complex a non-template class which uses double and remove all template-related code, so the definition of operator>>() is essentially correct.

What changes when I make Complex a template?

2 Answers

Friend functions are not members so they aren't implicitly templates. Declaration there suggests existence of non-template operator for instantiated type Complex<int>. You may use

template<typename U> 
friend istream& operator>>(istream& input, Complex<U>& c1);

template<typename U> 
friend ostream& operator<<(ostream& output, Complex<U>& c1);

The problem is that currently the overloaded friend functions are ordinary functions. If you want to make them as function templates instead then you need to change the friend declarations inside the class to as shown below.

To be more formal, in your original code operator<< and operator>> for class template Complex<> are not function templates, but “ordinary” functions instantiated with the class template if needed. That is, they are templated entities.

There are 2 ways to solve the problem, both of which are given below.

Solution 1

template<typename T>
class Complex
{
    //other members as before
    
    //friend declarations
    template<typename U>
    friend istream& operator>>(istream& input, Complex<U>& c1);
    template<typename V>
    friend ostream& operator<<(ostream& output, Complex<V>& c1);
    
    //other members as before
};

Demo

Solution 2

//forward declarations
template<typename T>
class Complex;
template<typename U>
istream& operator>>(istream& input, Complex<U>& c1);

template<typename V>
ostream& operator<<(ostream& output,const Complex<V>& c1);

template<typename T>
class Complex
{
    T real, img;
public:
    Complex():real(0), img(0){}
    
    //friend declarations
    
    friend istream& operator>> <T>(istream& input, Complex<T>& c1);
    
    friend ostream& operator<< <T>(ostream& output,const Complex<T>& c1);
    
    Complex operator+(Complex& c1);
};

Demo

Related