1

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.

7
  • 3
    void operator>>(const istream& in, const TestClass<T,L>& q) -- How are you going to modify q if it is const? Commented Apr 20, 2017 at 17:09
  • 2
    off topic: usually operator>>() return a std::istream (the same it, in your case), not void
    – max66
    Commented Apr 20, 2017 at 17:12
  • @max66, as far as my understanding till now, Its not mandatory to return an istream. is it ? Commented Apr 20, 2017 at 17:15
  • 2
    @SurajeetBharati When it comes to operator overloading, there's a bunch of practices that are not technically mandatory, but you basically always want to do. Returning the stream from << and >> is one of those. cppreference has a whole page of these things. Commented Apr 20, 2017 at 17:17
  • 2
    @SurajeetBharati, While you're allowed to return void, it makes your class inconsistent with every other streamable class. cin >> an_int >> a_test_class; works, but cin >> a_test_class >> an_int; doesn't. That's really strange behaviour. In addition, the common if (cin >> foo) pattern doesn't work with your class.
    – chris
    Commented Apr 20, 2017 at 17:21

1 Answer 1

2

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];
            }       
        }
};
4
  • So, I need to to specify different template for my friend function while that is not the case member functions. right ? Commented Apr 20, 2017 at 17:21
  • 1
    @SurajeetBharati, Yes, cppreference has several scenarios and examples of friends. Without the template, you're saying there's a non-template free operator>>(istream&, TestClass<float, 3>&). With the template, you're saying there's a free template and that every specialization of it is a friend (which is actually a bit overly permissive, since only the corresponding specialization needs to be a friend).
    – chris
    Commented Apr 20, 2017 at 17:23
  • @SurajeetBharati: Right. Basically unless that friend function is also templated you are forced to write an overload for every instantiation of your TestClass like this.
    – AndyG
    Commented Apr 20, 2017 at 17:24
  • @SurajeetBharati: Or you go with the slightly more complicated syntax like here
    – AndyG
    Commented Apr 20, 2017 at 17:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.