I'm trying to make the multiplication operator a friend of a template class named TVector3. I have read that I could make a forward declaration of the friend function before declaring it in the class declaration however my attempts of doing so were futile. I know I could simply define the friend function instead of declaring it, but I want it to work with forward declaration technique.
In particular I was trying to implement this solution for my case. I found this post too were David Rodriguez gives a solution (the third version) but I don't know what I'm doing wrong.
I compile using 'g++ template.cpp tempmain.cpp a' and The compiler (g++) gives the following error:
undefined reference to 'ray::TVector3 ray::operator*(float, ray::TVector3 const&)'
for the following code:
template.h:
#ifndef TVECTOR_H
#define TVECTOR_H
#include <cmath>
namespace ray
{
//forward declarations
template <class T> class TVector3;
template <class T> TVector3<T> operator* (T, const TVector3<T> &);
template <class T>
class TVector3 {
public:
union {
struct {
T x, y, z;
};
T xyz[3];
};
//function needed
friend TVector3<T> operator*<T> (T, const TVector3<T> &);
};
}
#endif
template.cpp:
#include "template.h"
using namespace ray;
//friend operator function
template<class T> TVector3<T> operator * (T f, const TVector3<T> &v)
{
return TVector3<T>(f * v.x, f * v.y, f * v.z);
}
//instantiate template of type float
template class TVector3<float>;
tempmain.cpp:
#include <iostream>
#include "template.h"
int main()
{
ray::TVector3<float> v1, v2;
v2.x = 3;
v1 = 4.0f * v2; //this reports as undefined
std::cout << v1.x << "\n";
return 0;
}
That is the full source code. What am I doing wrong?
As a general rule of thumb, templates should be defined in the header. If you define them in the cpp file, you will need to manually instantiate the template. You are doing it for the class template, but you are not instantiating the operator*
template.
template TVector3<T> operator*<T> (T, const TVector3<T> &);
Additionally, I would recommend that instead of using a templated operator*
you used a non-template free function by declaring and defining it inside the class template:
template <class T>
class TVector3 {
//function needed
friend TVector3<T> operator*(T f, const TVector3<T> & v) {
return TVector3<T>(f * v.x, f * v.y, f * v.z);
}
};
This has the advantages of free functions (it allows conversions on the first argument), and of templates (it will generate the free function on demand --i.e. no need to provide all the implementations manually) as well as limited visibility (it will only be accessible for lookup through ADL)