8

trying to get the operator to work, but throwing me bunch of errors:

my header file

template <unsigned short n>
class Vector {
public:
    std::vector<float> coords;

    Vector();
    Vector(std::vector<float> crds);
    friend std::ostream& operator <<(std::ostream& out, const Vector& v);
};

template <unsigned short n>
Vector<n>::Vector() {
coords.assign(n, 0.0);
}

template <unsigned short n>
std::ostream& operator<<(std::ostream& out, const Vector<n>& v) {
out << "(" << v.coords[1] << " - " << v.coords[2] << ")";
return out;
}

test file

#include <iostream>
#include "vector.h"
using namespace std;

int main() {
Vector<3> toomas;
cout << toomas;

}

error:

C:\CodeBlocks\kool\praks3\vector.h|14|warning: friend declaration 'std::ostream& operator<<(std::ostream&, const Vector&)' declares a non-template function|

C:\CodeBlocks\kool\praks3\vector.h|14|note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) |

obj\Debug\test.o||In function `main':|

C:\CodeBlocks\kool\praks3\test.cpp|8|undefined reference to `operator<<(std::ostream&, Vector<(unsigned short)3> const&)'|

Jaanus
  • 16,161
  • 49
  • 147
  • 202
  • You shouldn't declare it a friend in the first place, because you are not accessing anything private. - Also a std::vector might be a bit heavyweight for a math Vector... – UncleBens Mar 12 '11 at 20:27

2 Answers2

11

Please look at the error, it says,

friend declaration 'std::ostream& operator<<(std::ostream&, const Vector&)' declares a non-template function|

That means you need to make the operator<< a template function.

So in the class, you've to declare it as:

template<unsigned short m> //<----note this: i.e make it template!
friend std::ostream& operator <<(std::ostream& out, const Vector<m>& v);

Then define it as,

template <unsigned short m>
std::ostream& operator<<(std::ostream& out, const Vector<m>& v) {
   out << "(" << v.coords[1] << " - " << v.coords[2] << ")";
   return out;
}
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • You mean **unsigned short m** – Erik Mar 12 '11 at 18:26
  • @Erik: No I mean, make it template. However, you can choose any name be it `m`, `a`,`b`. etc. but don't choose `n` because it's the argument of enclosing class template! – Nawaz Mar 12 '11 at 18:31
  • 3
    Yuck. Why should `operator <<` for `Vector` have access to privates of `Vector`? – Ben Voigt Mar 12 '11 at 18:32
  • @Ben: You've a point. But I was explaining the friend part, and the error he is getting! – Nawaz Mar 12 '11 at 18:34
  • @Nawaz: You do actually mean **unsigned short m** :P - you used **unsigned int m** in declaration and **unsigned short m** in definition – Erik Mar 12 '11 at 18:37
  • @Erik: Oops.. I thought you were talking about `m` vs `n` thingy, when in fact it's `int` vs `short`. Anyway corrected! – Nawaz Mar 12 '11 at 18:39
  • @Nawaz: well this worked great, thanks, but i do not understand one thing..why doesn't the template before my `class Vector ` work for the ostream? why must i write the template twice, but for example i did not have to do that for my constructor. i don't really understand the concept hehe. and why we are using m suddenly, but in constructors we use n. – Jaanus Mar 13 '11 at 07:29
  • @Jaanus: `template` is only for the class, not for the function inside it. If you want to make the function template as well, then you've to do as I said, or do as Ben's solution second is! – Nawaz Mar 13 '11 at 08:59
7

Just define the friend function inside the class.

template <unsigned short n>
class Vector
{
public:
    std::vector<float> coords;

    Vector();
    Vector(std::vector<float> crds);
    friend std::ostream& operator <<(std::ostream& out, const Vector& v)
    {
        out << "(" << v.coords[1] << " - " << v.coords[2] << ")";
        return out;
    }
};

template <unsigned short n>
Vector<n>::Vector()
{
    coords.assign(n, 0.0);
}


int main()
{
    Vector<3> toomas;
    cout << toomas;
}

Tested: http://ideone.com/LDAR4

Or, declare the template function beforehand, using a forward prototype:

template <unsigned short n>
class Vector;

template <unsigned short n>
std::ostream& operator <<(std::ostream& out, const Vector<n>& v);

template <unsigned short n>
class Vector
{
public:
    std::vector<float> coords;

    Vector();
    Vector(std::vector<float> crds);
    friend std::ostream& operator << <>(std::ostream& out, const Vector& v);
};

template <unsigned short n>
Vector<n>::Vector()
{
    coords.assign(n, 0.0);
}

template <unsigned short n>
std::ostream& operator <<(std::ostream& out, const Vector<n>& v)
{
    out << "(" << v.coords[1] << " - " << v.coords[2] << ")";
    return out;
}

Tested: http://ideone.com/8eTeq

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I've been reading this post as I have a very similar problem. Could you explain why ``ostream& operator <<`` needs to be initialized and defined inside the class? And also, why it has to be a friend function ? For instance, I can overload operator ``+=`` and I don't have to give the definition inside my class, neither do I have to declare it as a friend. Why ``ostream& operator <<`` is so special? – zorro47 Jul 03 '19 at 10:41
  • 1
    @zorro47: It doesn't have to be a friend function. OP wanted it that way. On the other hand, your comment's comparison to `operator+=` is faulty. First, `operator+=` overload CANNOT be a friend, and it CANNOT be a free function, it's required to be a non-static member. Second, for `operator+=` the class instance is the left-hand operand, for `operator<<(ostream&, MyClass&)` the class instance is the right operand. When the class instance is the right operand, you cannot provide the operator as a class member. – Ben Voigt Jul 03 '19 at 15:19
  • @zorro47: And right there in my answer has always been an example (second code block) of how to define `operator<<` outside the class, so why are you asking if that is possible? – Ben Voigt Jul 03 '19 at 15:20
  • 1
    The method you presented in the second block I figured out on my own as well but it does not work every time I try to apply to my code. However, when I define it as friend inside the class it suddenly starts working. This happens only with ``ostream&`` Strange to me. That is why I was asking. – zorro47 Jul 03 '19 at 21:25
  • I'm having the exact same issue – frankelot Apr 09 '20 at 03:37