6

This is my code:

mov.h

#include <iostream>

template< class T>
class Movie {
public:
    Movie(T in) {
        a = in;
    }

    friend std::ostream& operator<<(std::ostream& os, const Movie<T>& movie);
private:
    T a;
};

template<class T>
std::ostream& operator<<(std::ostream& os, const Movie<T>& movie) {
    return os;
}

main.cpp

#include "mov.h"

int main() {
    Movie<int> movie1(1);

    std::cout << movie1 << std::endl;

    return 0;
}

I try to compile this code, and I get the error:

Error 1 error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Movie<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$Movie@H@@@Z) referenced in function _main    c:\Users\Adi\documents\visual studio 2013\Projects\bdika01\bdika01\main.obj bdika01
Error   2   error LNK1120: 1 unresolved externals   c:\users\adi\documents\visual studio 2013\Projects\bdika01\Debug\bdika01.exe    1   1   bdika01

If I try the code inline like this it's okay:

mov.h

 #include <iostream>

 template<class T>
 class Movie {
 public:
     Movie(T in) {
         a = in;
    }

    friend std::ostream& operator<<(std::ostream& os, const Movie<T>& movie){
        return os;
    }
private:
    T a;
};

What can I do if I want to separate the defination and declaration?

Thanks.

David G
  • 94,763
  • 41
  • 167
  • 253
user11001
  • 372
  • 3
  • 14
  • FWIW, it works if you template the declaration or use the specific type in the definition. – chris Aug 13 '14 at 22:49

1 Answers1

6
template <typename T> class Movie;

template<class T>
std::ostream& operator<<(std::ostream& os, const Movie<T>& movie);

template< class T>
class Movie {
  friend std::ostream& operator<< <T>(std::ostream& os, const Movie<T>& movie);
};

template<class T>
std::ostream& operator<<(std::ostream& os, const Movie<T>& movie){
    return os;
}

In your original code, you befriend a non-template function that just happens to take the right instantiation of Movie<> as a parameter. So, every time a Movie<T> is instantiated, a corresponding non-template operator<< is declared (but not defined) in the enclosing namespace scope. friend declarations are strange this way.

In addition, you declare and define a function template named operator<< (which is not a friend of any instantiation of Movie). However, overload resolution prefers non-templates, other things equal.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • +1 for fast correct solution, but you should provide an explanation as to why. Contextualize ... – Fantastic Mr Fox Aug 13 '14 at 22:50
  • Why not just make `operator<<` a template within `Movie`? – David G Aug 13 '14 at 22:53
  • @0x499602D2: if one is willing to implement `operator<<` in-class, then one doesn't have to make it a template. The OP actually has it working this way - see "If I try the code inline like this it's okay" section of the question. But he or she specifically asked how to make it work with out-of-class implementation. – Igor Tandetnik Aug 13 '14 at 22:54