0

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

Community
  • 1
  • 1
user1668903
  • 407
  • 5
  • 11

2 Answers2

2

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;
}
Quentin Perez
  • 2,833
  • 20
  • 22
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.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • And could you explain why `#include "Number.h"` is more common in situations when there is `template` – user1668903 Dec 26 '12 at 12:27
  • @user1668903 I don't really understand the question, I'm afraid. Whenever you instantiate a template, for example `Number`, the compiler needs to be able to generate the class `Number` with all occurrences of `T` replaced with `int`. To do that, it needs to be able to see all of the code for `Number`, so the header file must contain both the header and the implementation. – Joseph Mansfield Dec 26 '12 at 12:37
  • Sorry , I mean that why people won't always `#include "Number.cpp"` in `Number.h` rather than `#include "Number.h"` in `Number.cpp` – user1668903 Dec 26 '12 at 12:47
  • @user1668903 Because a normal implementation file (when it is not a template implementation) needs to be compiled separately. For example, if you have a class `T` that is not templated and there are two files `T.h` and `T.cpp`, you will at some point compile `T.cpp`, which must include the definition of the class from `T.h`. If `T.cpp` doesn't include `T.h`, it won't compile because there will be no class definition. But with your template implementation, `Number.cpp`, it does not need to be compiled separately. In fact, it needs to be included in every translation unit that makes use of it. – Joseph Mansfield Dec 26 '12 at 13:05