I am creating a matrix class and have the following declaration. The intent is to build a scalable matrix class that has algorithms that are flexible and can be run on various kinds of platforms -
template<typename T> class xss_matrix{
public:
xss_matrix(int i=0, int j=0):
max_row(i), max_col(j)
{
/*create space for the (0,0) entry*/
matrix[0]= (T*)(malloc(sizeof(T)));
};
~xss_matrix()
{
};
void add_entry(int row, int col, T val);
T get_entry(int row, int col);
friend ostream& operator<<(ostream &out, const xss_matrix<T> &m_xss_matrix);
private:
/*Internal variables*/
int max_row, max_col;
/*Internal data structures*/
T* matrix[];
/*Internal methods*/
void add_columns(int row, int col);
void add_rows(int row, int col);
};
#endif
then I overload the stream operator -
/*Overloaded stream operators*/
template<typename T> std::ostream& operator<<(ostream &out, const xss_matrix<T> &m_xss_matrix)
{
for(int ii = 0; ii < m_xss_matrix.max_row+1; ii+=1){
for(int jj = 0; jj < m_xss_matrix.max_col+1; jj+=1){
std::cout <m_xss_matrix.matrix[ii][jj] << " ";
}
std::cout << std::endl;
}
}
but when I run this -
#include "xss_matrix.hpp"
int main(int argc, char** argv)
{
xss_matrix<double>* foo = new xss_matrix<double>;
xss_matrix<double> bar;
foo->add_entry(0,0,2.35);
foo->add_entry(0,1,1.75);
foo->add_entry(1,0,1.50);
foo->add_entry(1,1,2.00);
std::cout << *foo;
}
I get a linker error -
[mitra@vlch-mitra xss_src]$ make
g++ -c -o main.o main.cpp -g -I. -fpermissive
In file included from xss_matrix.hpp:1,
from main.cpp:1:
xss_matrix.h:36: warning: friend declaration `std::ostream& operator<<(std::ostream&, const xss_matrix<T>&)' declares a non-template function
xss_matrix.h:36: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
g++ -o main main.o -g -I. -fpermissive
main.o: In function `main':
/home/mitra/dv/libparser/xss_src/main.cpp:15: undefined reference to `operator<<(std::basic_ostream<char, std::char_traits<char> >&, xss_matrix<double> const&)'
collect2: ld returned 1 exit status
make: *** [main] Error 1
[mitra@vlch-mitra xss_src]$
I do not understand the compiler warning which I am sure causes the linker failure. Can someone help? The version of gcc is 4.4.7-4 Thanks, Raj
The friend declaration declares a non-template function named operator<<
; each instantiation of xss_matrix
stamps out a new declaration. None of those functions are actually defined.
Then there's a single definition of a function template, overloading all those declarations. It is not declared a friend.
However, during overload resolution, non-template overloads win, other things equal. So the compiler chooses one of those. But it's never defined, so the linker complains.
If you really want to befriend a template, it has to be done this way:
template<typename T> class xss_matrix;
template<typename T>
std::ostream& operator<<(ostream &out, const xss_matrix<T>& m_xss_matrix);
template<typename T> class xss_matrix {
// Implementation here
template <typename U>
friend std::ostream& operator<<(ostream &out, const xss_matrix<U>& m_xss_matrix);
};
template<typename T>
std::ostream& operator<<(ostream &out, const xss_matrix<T> &m_xss_matrix) {
// Implementation here
}
However, it's usually easier to have a non-friend function template simply delegate to a public member function:
template<typename T> class xss_matrix {
public:
void print(ostream& out) {
// Write data to out
}
};
template<typename T>
std::ostream& operator<<(ostream &out, const xss_matrix<T> &m_xss_matrix) {
m_xss_matrix.print(out);
return out;
}