Search code examples
c++templatesoperator-overloadingfriend

Template Class with stream operator overloading


I am trying to get a better understanding on some advanced staffs of C++. I am trying to understand stream operator overloading , friend function and template now. I am trying to learn all these things in a single code segment.

So, I am trying to implement a template class which will just contain an array, which I want to populate with stream operator. So,I came up with this.

#include <iostream>
using namespace std;

template<class T, int L>
class TestClass
{
    private:
        T data[L];
    public:
        friend void operator>>(const istream&, const TestClass<T,L>&);
};

template<class T, int L>
void operator>>(const istream& in, const TestClass<T,L>& q)
{
    for(int i = 0; i < L; i++)
    {
        in >> q.data[i];
    }
}

int main() {
    TestClass<float, 3> Q;
    cin >> Q;

    return 0;
}

This is pretty easy code segment. But, I am getting following error on compilation

undefined reference to `operator>>(std::istream const&, TestClass<float, 3> const&)'

with the following warning

warning: friend declaration 'void operator>>(const istream&, const TestClass<T, L>&)' declares a non-template function [-Wnon-template-friend]|

I know, I am doing some rookie mistake, as I am pretty new to this things. It will be great if someone helps to run this successfully.


Solution

  • The issue is two-fold:

    1. Your friend function should also be a template
    2. You are passing the istream and TestClass as const. Remove that

    Here is updated code:

    template<class T, int L>
    class TestClass
    {
        private:
            T data[L];
        public:
            template<class U, int M>
            friend void operator>>(istream&, TestClass<U,M>&);
    };
    
    template<class T, int L>
    void operator>>(istream& in, TestClass<T,L>& q)
    {
        for(int i = 0; i < L; i++)
        {
            in >> q.data[i];
        }
    }
    

    Demo


    Edit: Other equally valid approaches

    Slightly different syntax to declare the friend and everything will work Demo:

    template<class T, int L>
    class TestClass
    {
        private:
            T data[L];
        public:
            friend void operator>> <>(istream&, TestClass&);
    };
    

    (Thanks @chris). This format (with the <>) differs from the above example in that the above is technically declaring all instantiations of operator>> to be a friend whereas this one only has a one-to-one relationship.

    Alternatively you could include the definition along with the friend declaration Demo:

    template<class T, int L>
    class TestClass
    {
        private:
            T data[L];
        public:
            friend void operator>>(istream& in, TestClass& q){
                for(int i = 0; i < L; i++)
                {
                    in >> q.data[i];
                }       
            }
    };