Undefined reference to friend function in template class - c++

The following codes are in file Heap.h
template <typename T>
class Heap {
public:
Heap();
Heap(vector<T> &vec);
void insert(const T &value);
T extract();
T min();
void update(int index, const T &value);
/* for debug */
friend ostream &operator<< (ostream &os, const Heap<T> &heap);
#if 0
{
for (int i = 0; i < heap.vec_.size(); i++) {
os << heap.vec_[i] << " ";
}
return os;
}
#endif
private:
void minHeapify(int index);
int left(int index);
int right(int index);
int parent(int index);
void swap(int, int);
vector<T> vec_;
};
template <typename T>
ostream &operator<<(ostream &os, const Heap<T> &heap)
{
for (int i = 0; i < heap.vec_.size(); i++) {
os << heap.vec_[i];
}
return os;
}
In a testheap.cpp file, I use this template class, when I compile, an undefined reference to the << operator overloading function error occur. Confused with this situation.
When I put the definition of the function in the class, it works.
The OS is Ubuntu, compiler is g++.

The following should work:
template <typename T>
class Heap {
public:
...
template<class U>
friend ostream &operator<<(ostream &os, const Heap<U> &heap);
...
};
template <typename T>
ostream &operator<<(ostream &os, const Heap<T> &heap)
{
...
}

Try this :
template <typename T2>
friend ostream &operator<< (ostream &os, const Heap<T2> &heap);
I had the same problem. Here is the question

Related

How to override output operator (<<) as a function template outside a class template

I am reading Section 2.4 of the book "C++ tempalte, a complete guide".
I tried to override output operator (<<) as a function template outside the class template Stack<>.
Below is my code, but it doesn't work.
#include <iostream>
#include <string>
#include <vector>
template<class T>
class Stack
{
private:
std::vector<T> v;
public:
void push(T a);
void printOn(std::ostream & os) const;
template <typename U>
friend std::ostream& operator<< (std::ostream& out, const Stack<U> & s);
};
template<typename T>
std::ostream& operator<< (std::ostream out, const Stack<T> & s)
{
s.printOn(out);
return out;
}
template<class T>
void Stack<T>::push(T a)
{
v.push_back(a);
}
template<class T>
void Stack<T>::printOn(std::ostream & out) const
{
for(T const & vi : v)
{out << vi << " ";}
}
int main()
{
Stack<int> s1;
s1.push(12);
s1.push(34);
std::cout << s1;
}
You are just omitting the &, which makes the operator<< inside and outside the class have different function signatures, they are both valid for std::cout << s1, hence the ambiguity
template<typename T>
std::ostream& operator<< (std::ostream& out, const Stack<T> & s)
// ^
{
s.printOn(out);
return out;
}

How to overload ostream for a member struct of a templated class

I'm implementing a dictionary in C++ using a binary tree, each node in my tree has a key(int), item(string) and left and right child.
During this implementation, I overloaded the ostream operator for my BinaryTree class to print out the contents of the tree.
Additionally, I overloaded the ostream to work with Node pointers that would then print out the key and the item of that node.
This worked fine. However when I tried to then make the tree a template to work with any type for my key or item overloading these operators became more difficult.
I isolated the problem to make it easier to work on, additionally, I have tried playing around with both a node and a node pointer to see if I can get one to work without the other.
Here is the class I have made to test the problem, this class is not templated and works fine.
test.h
class myClass
{
public:
using Key = int;
myClass(Key);
friend std::ostream & operator<<(std::ostream &, const myClass &);
private:
struct Thing {
Key data;
Thing();
Thing(Key);
};
Thing* B;
Thing A;
void disp(std::ostream &) const;
friend std::ostream & operator<<(std::ostream &, myClass::Thing);
friend std::ostream & operator<<(std::ostream &, myClass::Thing *);
};
test.cpp
myClass::Thing::Thing(Key Num) { data = Num; }
myClass::myClass(Key Num)
{
A = Thing(Num); B = &A;
}
void myClass::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
std::ostream & operator<<(std::ostream & os, const myClass & c)
{
c.disp(os); return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing th)
{
os << th.data; return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing *th)
{
os << th->data; return os;
}
With this class, I can easily make an instance of my class and std::cout it giving the output as expected.
Then turning this class into a template:
template <class T> class myTemplate
{
public:
using Key = T;
myTemplate(Key);
template<class A>
friend std::ostream & operator<<(std::ostream &, const myTemplate<A> &);
private:
struct Thing;
Thing A;
Thing* B;
void disp(std::ostream &) const;
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing);
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing *);
};
template <class T> struct myTemplate<T>::Thing
{
T data;
Thing() = default;
Thing(Key);
};
//Create new thing A with B a pointer to A
template <class T> myTemplate<T>::myTemplate(Key Num)
{
A = Thing(Num);
B = &A;
}
//Displays Node A & B
template <class T> void myTemplate<T>::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
template <class T> myTemplate<T>::Thing::Thing(Key Num)
{
data = Num;
}
//Overloading << will call disp function, in turn print A & B to stream
template<class T> std::ostream & operator<<(std::ostream & os, const myTemplate<T> & c)
{
c.disp(os); return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing th)
{
os << th.data; return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing *th)
{
os << th->data; return os;
}
However with myTemplate when I tried in the main():
myTemplate Template(5);
cout << Template;
The code will not compile as I get the error:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'const myTemplate<std::string>::Thing' (or there is no acceptable conversion)
Additionally commenting out the line:
os << A << std::endl;
So only B is being outputted to the stream, the code will compile. However the data of B is not outputted, only the memory address of B.
I have noticed that using breakpoints when trying to output B the code does not even use the overload function I defined. This is not the case for the non-templated class as the overloads I defined are used for both A and B.
So what is the correct way to overload the ostream operator to work for the struct member?
Apologises for the long winded question, felt I should include what I had determined myself.
Since template implementation is going to be in a single translate unit(header file) itself, you are not going to gain anything more, by tearing the things apart. Therefore, keep the definitions and non-member functions inside the class itself, which will provide you with much clear code and also improve the readability of the template class:
See this
#include <iostream>
template <class T> class myTemplate
{
public:
using Key = T;
private:
struct Thing
{
T data;
Thing() = default;
Thing(Key Num) : data(Num) {}
};
Thing A;
Thing* B = nullptr;
public:
myTemplate(Key Num) : A(Thing(Num)), B(&A) {}
friend std::ostream & operator<<(std::ostream& out, const myTemplate &obj)
{
return out << obj.A << std::endl << obj.B << std::endl;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing thing)
{
return out << thing.data;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing *thing)
{
return out << thing->data;
}
};
int main()
{
myTemplate<int> obj(10);
std::cout << obj;
return 0;
}
Update: If the final aim of providing that two operator<< overloads to the struct Thing is just to conveniently call in the operator<< of the myTemplate class, then you do not need that, rather simply print the data directly in operator<< of the myTemplate class. That will again reduce significate amount of codes(if that is the case!).
Nevertheless, now you can provide a specialization for the non-member(friend) function(i.e, operator<<) for the myTemplate class, as follows:
template <class T> class myTemplate; // forward declaration
template <class T> std::ostream& operator<<(std::ostream& out, const myTemplate<T> &obj);
template <class T> class myTemplate
{
private:
using Key = T;
private:
template <class Type = T> struct Thing
{
Type data;
Thing() = default;
Thing(const Key Num) : data(Num) {}
};
private:
Thing<> A;
Thing<> *B = nullptr;
public:
myTemplate(const Key Num) : A(Thing<>(Num)), B(&A) {}
friend std::ostream & operator<<<>(std::ostream& out, const myTemplate &obj);
};
template <class T> std::ostream & operator<<(std::ostream& out, const myTemplate<T> &obj)
{
return out << obj.A.data << std::endl << obj.B->data << std::endl;
}

How do I declare a template friend function that is type-specific in my template class?

I've recently learned that there are two ways to declare a template friend class or function. For example, to declare a template friend class, you may do this
template <typename T>
class goo
{
template <typename T>
friend class foo;
};
or this
template <typename T>
class goo
{
friend class foo <T>;
};
These two declarations are in fact different. The former allows you to use any type of template friend class foo with any type of template friend class goo. Where as the latter only allows you to use the same type such that you may do foo<int> with goo<int> but not foo<int> with goo<char>.
In the header file below, I try to use the latter form of the declaration to make my template friend function friend std::ostream& operator<<(std::ostream&, const Array<T>&); more type-specific in an effort to make my program more encapsulated.
//ARRAY_H
#include <iostream>
#include "Animal.h"
const int DefaultSize = 3;
template <typename T> // declare the template and the paramenter
class Array // the class being parameterized
{
public:
Array(int itsSize = DefaultSize);
Array(const Array &rhs);
~Array() { delete[] pType; }
// operators
Array& operator=(const Array&);
T& operator[](int offSet) { return pType[offSet]; }
const T& operator[](int offSet) const { return pType[offSet]; }
// accessors
int GetSize() const { return itsSize; }
// friend function
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
private:
T *pType;
int itsSize;
};
template <typename T>
Array<T>::Array(int size = DefaultSize) :itsSize(size)
{
pType = new T[size];
for (int i = 0; i < size; i++)
pType[i] = static_cast<T>(0);
}
Array<Animal>::Array(int AnimalArraySize) :itsSize(AnimalArraySize)
{
pType = new Animal[AnimalArraySize];
}
template <typename T>
Array<T>::Array(const Array &rhs)
{
itsSize = rhs.GetSzie();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
}
template <typename T>
Array<T>& Array<T>::operator=(const Array &rhs)
{
if (this == &rhs)
return *this;
delete[] pType;
itsSize = rhs.GetSize();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
return *this;
}
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray)
{
for (int i = 0; i < theArray.GetSize(); i++)
output << "[" << i << "]" << theArray[i] << std::endl;
return output;
}
#endif
However, I receive a compiler error "error C2143: syntax error : missing ';' before '<'" for line 23 which is friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);.
When using the former form of the declaration by changing line 23 to this
template <typename T>
friend std::ostream& operator<<(std::ostream&, const Array<T>&);
My program executes without any errors.
I assume I cannot use the same syntax from type-specific template friend classes for type-specific template friend functions, or that I may be missing some kind of forward declaration. I've searched through stack-overflow and the closest topic I could find for this problem is here, but they only discuss type-specific template friend classes. I am unable to find a topic that discusses the correct syntax for using a template friend function in this way.
If this is a syntax error, what is the correct way to declare my type-specific template friend function? If this is not a syntax error, why will my program not compile?
Here are the rest of my project files for your reference. The desired behavior of my program is to show how a parametrized array uses a template to create multiple instances of different array types.
//ANIMAL_H
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
class Animal
{
public:
// constructors
Animal();
Animal(int);
~Animal();
// accessors
int GetWeight() const { return itsWeight; }
void SetWeight(int theWeight) { itsWeight = theWeight; }
// friend operators
friend std::ostream& operator<<(std::ostream&, const Animal&);
private:
int itsWeight;
};
#endif
//ANIMAL.CPP
#include "Animal.h"
#include <iostream>
Animal::Animal() :itsWeight(0)
{
std::cout << "animal() ";
}
Animal::Animal(int weight) : itsWeight(weight)
{
std::cout << "animal(int) ";
}
Animal::~Animal()
{
std::cout << "Destroyed an animal...";
}
std::ostream& operator<<(std::ostream& theStream, const Animal& theAnimal)
{
theStream << theAnimal.GetWeight();
return theStream;
}
//MAIN.CPP
#include <iostream>
#include "Animal.h"
#include "Array.h"
void IntFillFunction(Array<int>& theArray);
void AnimalFillFunction(Array<Animal>& theArray);
int main()
{
Array<int> intArray;
Array<Animal> animalArray;
IntFillFunction(intArray);
AnimalFillFunction(animalArray);
std::cout << "intArray...\n" << intArray;
std::cout << "\nanimalArray...\n" << animalArray << std::endl;
std::cin.get();
return 0;
}
void IntFillFunction(Array<int>& theArray)
{
bool Stop = false;
int offset, value;
while (!Stop)
{
std::cout << "Enter an offset (0-9) and a value. ";
std::cout << "(-1 to stop): ";
std::cin >> offset >> value;
if (offset < 0)
break;
if (offset > 9)
{
std::cout << "***Please use values between 0 and 9.***\n";
continue;
}
theArray[offset] = value;
}
}
void AnimalFillFunction(Array<Animal>& theArray)
{
Animal *pAnimal;
for (int i = 0; i < theArray.GetSize(); i++)
{
pAnimal = new Animal(i * 10);
theArray[i] = *pAnimal;
delete pAnimal;
}
}
You need to declare the function template before you refer to a specialization as a friend.
// Forward declare class template.
template <typename T> class Array;
// Declare function template.
template <typename T>
std::ostream& operator<<(std::ostream& os, const Array<T>& arr);
template <typename T>
class Array
{
//...
friend std::ostream& operator<< <>(
std::ostream& os, const Array<T>& arr);
//...
};
You need a forward declaration of the function template (just as you need with a class template) in order to friend a specialization. Your code should be:
template <typename T>
std::ostream& operator<<(std::ostream& output, const Array<T> &theArray);
template <typename T>
class Animal
{
// ...
friend std::ostream& operator<< <T>(std::ostream&, const Array<T>&);
};

Strange behavior of templated operator<<

I cant understand a behavior of operator<< in my class:
header:
#ifndef VECTOR_H_
#define VECTOR_H_
#include <string>
#include <iostream>
template<class T>
class Vector {
static const int EXPANDER = 10;
T* array;
int next;
int length;
void expand();
void contract();
public:
Vector();
Vector(const Vector& v);
void add(const T e);
T get(int index) const;
bool removeByIndex(int index);
bool remove(T e);
int size() const;
T operator[](int i) const;
T& operator+=(const T& t);
T operator+(const T& s);
friend std::ostream& operator<< (std::ostream& os, const Vector<T>& obj);
friend std::istream& operator>> (std::istream& is, Vector<T>& obj);
std::string toString();
~Vector();
};
#endif /* VECTOR_H_ */
vector.cpp
#include "Vector.h"
#include <string>
#include <sstream>
template<class T>
Vector<T>::Vector() {
length = EXPANDER;
next = 0;
array = new T[EXPANDER];
}
template<class T>
Vector<T>::Vector(const Vector& v) {
length = v.next + 1 + EXPANDER;
next = v.next;
array = new T[length];
for (int i = 0; i <= v.next; i++) {
array[i] = v.array[i];
}
}
template<class T>
void Vector<T>::add(const T e) {
if (next >= length - 1)
expand();
array[next++] = e;
}
template<class T>
T Vector<T>::get(int index) const {
if (index > next)
return -1;
return array[index - 1];
}
template<class T>
bool Vector<T>::removeByIndex(int index) {
if (index > next)
return false;
for (int i = index; i < length; i++) {
array[i] = array[i + 1];
}
next--;
contract();
return true;
}
template<class T>
bool Vector<T>::remove(T e) {
int index = -1;
for (int i = 0; i < next; i++) {
if (array[i] == e) {
index = i;
break;
}
}
if (index == -1)
return false;
return removeByIndex(index);
}
template<class T>
int Vector<T>::size() const {
return next;
}
template<class T>
void Vector<T>::expand() {
length += EXPANDER;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
void Vector<T>::contract() {
if (next + EXPANDER >= length)
return; // NO need to contract
length = next + EXPANDER + 1;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
T Vector<T>::operator[](int i) const {
return get(i);
}
template<class T>
T& Vector<T>::operator+=(const T& t) {
for (int i = 0; i < t.size(); i++) {
add(t.get(i));
}
return *this;
}
template<class T>
T Vector<T>::operator+(const T& s) {
this += s;
return this;
}
template<class T>
std::ostream& operator<< (std::ostream& os, Vector<T>& obj) {
os << obj.toString();
return os;
}
template<class T>
std::istream& operator>> (std::istream& is, Vector<T>& obj) {
int size;
T temp;
is >> size;
for (int i = 0; i < size; i++) {
is >> temp;
add(temp);
}
return is;
}
template<class T>
std::string Vector<T>::toString() {
using namespace std;
ostringstream sb;
sb << "Elements(" << size() << "): [";
for (int i = 0; i < next; i++) {
sb << array[i] << ", ";
}
string r;
r = sb.str();
r = r.substr(0, r.size() - 2) + string("]");
return r;
}
template<class T>
Vector<T>::~Vector() {}
and i run this code with main.cpp
#include "Vector.h"
#include "Vector.cpp"
#include <string>
#include <iostream>
using namespace std;
int main() {
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl;
}
the magic is in operator<< declaration in header. if i delete CONST modifier, compiler says: Undefined reference to operator<<, but with const it works. It is interesting that in my implementation, in cpp, I doesn't have CONST.
btw, how to solve warnings with warning: friend declaration declares a non-template function for operators?
You should learn how to boil this down to a Short, Self-Contained, Compilable Example aka Minimal Working Example.
Here's an SSCCE that demonstrates the problem:
#include <iostream>
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
T get() const { return m; }
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T>& v)
{
// accessing a private member leads to a compiler error here:
return o << "[function template]" << /*v.m*/ v.get();
}
// remove this function to get the same behaviour as in the OP
std::ostream& operator<<(std::ostream& o, Vector<int> const& v)
{
return o << "function" << v.m;
}
int main()
{
Vector<int> v(42);
std::cout << v;
}
Note that it's only about 30 lines long and fits onto one screen w/o scroll bars.
Now, the problem is based upon the friend declaration inside your class template:
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
This looks up a function named operator<< in the surrounding scopes, to befriend this already existing function. But it doesn't find any that matches those parameter type. Therefore, it declares a new function in the surrounding (= global) namespace. This function looks like this:
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
(in the global namespace)
Note: it can only be found via Argument-Dependent Lookup if it's only declared via a friend-declaration.
Now, you later declare a function template of the same name. But the compiler cannot know that you meant to befriend this function template when you wrote the friend declaration inside you class template before. So those two, the friend function and the function template, are unrelated.
What happens now is the usual overload resolution. The function template is preferred if you don't add a const, since you call it with a non-const argument:
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl; // v is not const
for this argument of type Vector<int>, the binding to Vector<int>& of the function template (specialization) is preferred over the binding to the Vector<int> const& of the friend function. Hence, the function template is chosen, which has a definition (function body) and everything compiles, links and works. Note that the function template is not befriended, but this doesn't raise an error since you don't use any private members.
Once you add the const to the function template, the function template is no longer a better match for the argument. As we have a function and a function template with the same overload "rank", the non-template is preferred. Ergo, the friend function is called, which has no definition => a linker error occurs.
The simplest solution is to define the friend function inside the class definition:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
};
A solution using forward-declarations:
template<class T>
class Vector;
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<< <T>(std::ostream& o, Vector<T> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
Now, the compiler can find the forward-declared function template and befriend this existing function (the specialization of the function template) instead of declaring a new function.
A solution befriending the whole function template:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
template<class U>
friend std::ostream& operator<<(std::ostream& o, Vector<U> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
In this solution, the friend-declaration declares a function template, and the later declaration at namespace scope following the class' definition redeclares this function template.

Problems with template in c++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Undefined symbol on a template operator overloading function
Here are my source code.
In Number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>
using std::istream;
using std::ostream;
template <class T> class Number;
template <class T>
ostream& operator<<(ostream&, const Number<T>&);
template <class T>
istream& operator>>(istream&, Number<T>&);
template <class T>
class Number{
public:
Number(const T &n) :i(n) {}
Number() :i(0) {}
T& operator+(const Number&rhs) const;
T& operator-(const Number&rhs) const;
T& operator*(const Number&rhs) const;
T& operator/(const Number&rhs) const;
friend ostream& operator<< <T> (ostream& , const Number<T>&);
friend istream& operator>> <T> (istream& , Number<T>&);
private:
T i;
};
#endif
And in Number.cpp
#include "Number.h"
template<class T>
T& Number<T>::operator+(const Number&rhs) const
{
return i+rhs.i;
}
template<class T>
T& Number<T>::operator-(const Number&rhs) const
{
return i-rhs.i;
}
template<class T>
T& Number<T>::operator*(const Number&rhs) const
{
return i*rhs.i;
}
template<class T>
T& Number<T>::operator/(const Number&rhs) const
{
return i/rhs.i;
}
template<class T>
ostream& operator<<(ostream&os , const Number<T>&rhs)
{
return os<< rhs.i;
}
template<class T>
istream& operator>>(istream&is , Number<T>&rhs)
{
return is >> rhs.i;
}
I cannot find out why there is
undefined reference to `std::istream& operator>><double>(std::istream&,Number<double>&)'
undefined reference to `Number<double>::operator+(Number<double> const&) const'
errors so on so forth
Use .hpp for template and you can't return reference on a temporary object.
number.h
#ifndef NUMBER_H
#define NUMBER_H
#include <iostream>
using std::istream;
using std::ostream;
template <class T> class Number;
template <class T>
ostream& operator<<(ostream&, const Number<T>&);
template <class T>
istream& operator>>(istream&, Number<T>&);
template <class T>
class Number{
public:
Number(const T &n) :i(n) {}
Number() :i(0) {}
T operator+(const Number&rhs) const; // Error Here return T not T&
T operator-(const Number&rhs) const;
T operator*(const Number&rhs) const;
T operator/(const Number&rhs) const;
friend ostream& operator<< <T> (ostream& , const Number<T>&);
friend istream& operator>> <T> (istream& , Number<T>&);
private:
T i;
};
#include <number.hpp>
#endif
number.hpp
#ifndef NUMBER_HPP
#define NUMBER_HPP
template<class T>
T
Number<T>::operator+(const Number& rhs) const
{
return i + rhs.i;
}
template<class T>
T
Number<T>::operator-(const Number&rhs) const
{
return i-rhs.i;
}
template<class T>
T
Number<T>::operator*(const Number&rhs) const
{
return i*rhs.i;
}
template<class T>
T
Number<T>::operator/(const Number&rhs) const
{
return i/rhs.i;
}
template<class T>
ostream& operator<<(ostream&os , const Number<T>&rhs)
{
return os<< rhs.i;
}
template<class T>
istream& operator>>(istream&is , Number<T>&rhs)
{
return is >> rhs.i;
}
#endif
main.cpp
#include <iostream>
#include <number.h>
int
main(int, const char**)
{
Number<double> value(1);
Number<double> add(3);
std::cout << value + add << std::endl;
std::cout << value * add << std::endl;
std::cout << value - add << std::endl;
std::cout << value / add << std::endl;
return 0;
}
The definitions of all those member functions need to be available to any translation unit that instantiates the template. Imagine a file that includes Number.h and attempts to use Number<int>. The compiler then needs to generate all of the code for Number instantiated with T as int. How can it do that if it's only seen Number.h? It doesn't know the definition of the member functions.
The fix is to put the definitions of your member functions (everything from Number.cpp) in Number.h. Alternatively, some people like to name Number.cpp as Number.tpp and, instead of #include "Number.h" in Number.cpp, put #include "Number.tpp" at the bottom of Number.h - basically inverting the inclusion so that the header always includes the implementation.