-1

I am having a compiler error implementing operator<< on a C++ template class. Here is the code:

#pragma once
#include <iostream>
using namespace std;
//a template class to process a pair of "things"
template <typename T>
class Pair
{
private:
    T first;
    T second;

public:
    Pair();
    Pair(T, T);
    friend ostream& operator<<(ostream&, Pair);  //also tried Pair<T>
};

template <typename T>
Pair<T>::Pair()
{ }

template <typename T>
Pair<T>::Pair(T one, T two)
{
    first = one;
    second = two;
}

template <typename T>
ostream& operator<<(ostream& out, Pair<T> other)
{
    out << "{ " << other.first << " and " << other.second << " }";
    return out;
}

//test code
int main(){
    Pair<string> words("red", "apple");
    cout << "words is " << words << endl;
}

I am getting linker 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 Pair<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@V?$Pair@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@@Z) referenced in function _main     
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    @super: Why would that answer it? It's fine to have templates in a source file if you know what you're doing. There's nothing magical about having templates in headers. – Bathsheba Nov 17 '21 at 20:23
  • You need to add an [explicit template instantiation](https://stackoverflow.com/questions/4933056/how-do-i-explicitly-instantiate-a-template-function) for the `string` version of your templated `operator <<`. – Andrej Podzimek Nov 17 '21 at 20:25
  • Whats the error you get? – kobi Nov 17 '21 at 20:25
  • @Bathsheba It wasn't this time, but it's usually the dupe for templates and unresolved external symbol. Didn't read all that carefully apparently. – super Nov 17 '21 at 20:29

2 Answers2

1

I found the mistake in class definition.

template <typename T>
friend ostream& operator<<(ostream&, Pair<T>);

I always forget that!

user4581301
  • 33,082
  • 7
  • 33
  • 54
1

The error message means that you declared a non-template friend function but does not define it for the template argument std::string of the class template Pair.

To avoid defining the function for different template arguments of the class template Pair you should define it within the class definition. In this case the compiler itself will define the function for various template arguments of the class template Pair when such a non-template friend function will be required.

The function can be declared and defined as it is shown in the demonstration program below.

Here is the demonstration program

#include <iostream>
#include <string>

template <typename T>
class Pair
{
private:
    T first;
    T second;

public:
    Pair();
    Pair( const T &, const T & );
    friend std::ostream & operator <<( std::ostream &out, const Pair<T> &other )
    {
        return out << "{ " << other.first << " and " << other.second << " }";
    }
};

template <typename T>
Pair<T>::Pair() : first(), second()
{ }

template <typename T>
Pair<T>::Pair( const T &one, const T &two ) : first( one ), second( two )
{
}

int main()
{
    Pair<std::string> p( "first", "second" );

    std::cout << p << '\n';
    std::cout << Pair<int>() << '\n';
}

The program output is

{ first and second }
{ 0 and 0 }
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335