The answer to @LogicStuff is absolutely right. I would like to clarify what exactly is happening in your code and how you can avoid this by using an alternative, since I believe that most C ++ programmers have encountered this problem at least once. Basically, when a template is created, let's say
MyVector<int> something;
then the friend declaration is automatically limited to the type of the template, in this case int , so the compiler generates
friend ostream& operator<<(ostream& os, MyVector<int> vt);
However, this is just an announcement. Last definition
template<class T> ostream& operator << (ostream& os, MyVector<T> vt)
has nothing to do with what exists for int , but because the first is a better match, whenever you try to execute
cout << something;
the compiler is trying to call the int version (which has no definition). This way you get a linker error.
Alternatively, it is widely used to define your statement embedded in a class, for example
friend ostream& operator << (ostream& os, MyVector<T> vt) { T size = vt.size(); for (T i = 0; i < size; i++) { os << "index " << i << " is " << vt.at(i) << endl; } return os; }
Now each instance of your MyVect creates the correct operator<< definition, limited to the corresponding template type. Note that the statement itself is not a member function , and it appears in the global namespace only through Argument Dependent Lookup (ADL) . This trick is called injection of a friendโs name, which is widely used in the Barton-Nackman trick , and you can successfully use it, because in a call like
cout << something;
the call is transferred to
operator<< (std::cout, something)
and becuase something is of type MyVector<int> , the definition of operator<< is through ADL. If your operator<< accepts, for example, a int as the second parameter, it will not be found through ADL, since the fundamental types do not have an associated namespace.