I am creating a template class for working with matrices and get an error when I try to use the overloaded << operator.

This is the code:

#include<iostream>
#include<string>
#include<conio.h>
using namespace std;

template <class T>
class matrice
{
	T **a;
	int m,n;
public: 
	matrice();
	matrice(int,int);
	matrice(FILE *);
	matrice(int,int,T **);
	matrice(matrice &x);
	~matrice(){}
	T& operator[](int i){return a[i];}
	friend T operator+(matrice<T> &a,matrice<T> &b);
	friend T operator+(T x,matrice<T> &b);
	friend T operator-(matrice<T> &a,matrice<T> &b);
	friend T operator-(T x,matrice<T> &b);
	friend T operator*(matrice<T> &a,matrice<T> &b);
	friend T operator*(T x,matrice<T> &b);
	friend T operator/(matrice<T> &a,matrice<T> &b);
	friend T operator/(T x,matrice<T> &b);
	bool operator ==(T &b);
	bool operator !=(T &b);
	friend ostream &operator <<(ostream &,matrice<T> &);
	T transpusa(){}//= si strcpy
	//virtual T determinant();
	T inversa(){}
	int getNrLinii(){
		return m;
	}
	int getNrColoane(){
		return n;
	}
	void setElement(int,int,T);
	
};

template <class T>
ostream &operator<<(ostream &os, matrice<T> &b){
	int i,j;
	for(i=0;i<b.m;i++){
		for(j=0;j<b.n;j++){
			os<<b[i][j]<<" ";
		}
		os<<endl;
	}
	return os;
}

matrice<char *>::matrice(int linii,int col):m(linii),n(col){
	int i,j;
	a=new char**[m];
	for(i=0;i<m;i++){a[i]=new char*[n];}
	for(i=0;i<m;i++)
		for(j=0;j<n;j++){
			cout<<"a["<<i<<"]["<<j<<"]= ";
			char *tmp;
			tmp=new char[100];
			cin>>tmp;
			a[i][j]=new char[strlen(tmp)+1];
			strcpy(a[i][j],tmp);
			delete tmp;
		}
}

//friend class Iterator;

void main (int argc, char * const argv[]) {
    matrice<char *> m1(2,2);
	cout<<m1;
	cout<<m1.getNrLinii();
	getch();
}

This is the error I get:

1>proiect.obj : error LNK2001: 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 matrice<char *> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$matrice@PAD@@@Z)

What am I missing? I am using visual studio express 2010

Edited 5 Years Ago by arthurav: n/a

Your declaration and definition don't match. The friend declared in your class is not a template while the defined operator<< is.

I have first compiled the project with gcc and what I have read about the CeePlusPlus standard is that it requires that Template <class T> before friend procedures.
I have removed that but still have that problem. It is now:

ostream &operator<<(ostream &os, matrice<T> &b){
	int i,j;
	for(i=0;i<b.m;i++){
		for(j=0;j<b.n;j++){
			os<<b[i][j]<<" ";
		}
		os<<endl;
	}
	return os;
}

Wrong solution. Add a template parameter to the declaration:

template <class U>
friend ostream &operator <<(ostream &,matrice<U> &);

Leave everything else as it was.

Either way (with or without template <class U> before the overloading) I get this error:

1>proiect.obj : error LNK2001: 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 matrice<char *> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$matrice@PAD@@@Z)

I guess I need to to it for you. :icon_rolleyes:

#include<iostream>
#include<string>
#include<conio.h>
using namespace std;

template <class T>
class matrice
{
    T **a;
    int m,n;
public: 
    matrice();
    matrice(int,int);
    matrice(FILE *);
    matrice(int,int,T **);
    matrice(matrice &x);
    ~matrice(){}
    T& operator[](int i){return a[i];}
    friend T operator+(matrice<T> &a,matrice<T> &b);
    friend T operator+(T x,matrice<T> &b);
    friend T operator-(matrice<T> &a,matrice<T> &b);
    friend T operator-(T x,matrice<T> &b);
    friend T operator*(matrice<T> &a,matrice<T> &b);
    friend T operator*(T x,matrice<T> &b);
    friend T operator/(matrice<T> &a,matrice<T> &b);
    friend T operator/(T x,matrice<T> &b);
    bool operator ==(T &b);
    bool operator !=(T &b);

    template <class U>
    friend ostream &operator <<(ostream &,matrice<U> &);

    T transpusa(){}//= si strcpy
    //virtual T determinant();
    T inversa(){}
    int getNrLinii(){
        return m;
    }
    int getNrColoane(){
        return n;
    }
    void setElement(int,int,T);

};

template <class T>
ostream &operator<<(ostream &os, matrice<T> &b){
    int i,j;
    for(i=0;i<b.m;i++){
        for(j=0;j<b.n;j++){
            os<<b[i][j]<<" ";
        }
        os<<endl;
    }
    return os;
}

matrice<char *>::matrice(int linii,int col):m(linii),n(col){
    int i,j;
    a=new char**[m];
    for(i=0;i<m;i++){a[i]=new char*[n];}
    for(i=0;i<m;i++)
        for(j=0;j<n;j++){
            cout<<"a["<<i<<"]["<<j<<"]= ";
            char *tmp;
            tmp=new char[100];
            cin>>tmp;
            a[i][j]=new char[strlen(tmp)+1];
            strcpy(a[i][j],tmp);
            delete tmp;
        }
}

//friend class Iterator;

void main (int argc, char * const argv[]) {
    matrice<char *> m1(2,2);
    cout<<m1;
    cout<<m1.getNrLinii();
    getch();
}

And yes, your code is still broken in operator[], but that's irrelevant to the linker error.

Thank you very much. It works.
I don't know, though, what am I missing in the following.

I have tried to apply the same principle for + operator.

I have added the following code to the template class:

template <class U>
friend matrice<U> operator+(matrice<U> &,matrice<U> &);

The friend function definition outside the template class definition:

template <class T>
matrice<double> operator+(matrice<double> &a,matrice<double> &b){
	matrice<double> c;
	c.m=a.m;
	c.n=a.n;
	c.a=new double*[m];
	for(int i=0;i<m;i++)c.a[i]=new double[n];
	for(int i=0;i<a.m;i++)
		for(int j=0;j<a.n;j++)c.a[i][j]=a.a[i][j]+b.a[i][j];
	return c;
}

I am running it like this:

matrice<double> m1("matrice1.txt");
matrice<double> m2("matrice2.txt");
cout<<m1;
cout<<endl;
cout<<m2<<endl;

matrice<double> m3;
m3=m1+m2;

The error is:

1>proiect.obj : error LNK2019: unresolved external symbol "class matrice<double> __cdecl operator+<double>(class matrice<double> &,class matrice<double> &)" (??$?HN@@YA?AV?$matrice@N@@AAV0@0@Z) referenced in function _main
1>proiect.obj : error LNK2019: unresolved external symbol "public: __thiscall matrice<double>::matrice<double>(void)" (??0?$matrice@N@@QAE@XZ) referenced in function _main

This is the full code:

#include<iostream>
#include<string>
#include<conio.h>
using namespace std;

template <class T>
class matrice
{
    T **a;
    int m,n;
public: 
    matrice();
    matrice(int,int);
    matrice(char *);
    matrice(int,int,T **);
    matrice(matrice &x);
    ~matrice(){}
    //T& operator[](int i){return a[i];}
    template <class U>
	friend U operator+(U x,matrice<U> &b);
    friend T operator-(matrice<T> &a,matrice<T> &b);
    friend T operator-(T x,matrice<T> &b);
    friend T operator*(matrice<T> &a,matrice<T> &b);
    friend T operator*(T x,matrice<T> &b);
    friend T operator/(matrice<T> &a,matrice<T> &b);
    friend T operator/(T x,matrice<T> &b);
    bool operator ==(T &b);
    bool operator !=(T &b);

	template <class U> 
    friend matrice<U> operator+(matrice<U> &,matrice<U> &);

    template <class U>
    friend ostream &operator <<(ostream &,matrice<U> &);

    T transpusa(){}//= si strcpy
    //virtual T determinant();
    T inversa(){}
    int getNrLinii(){
        return m;
    }
    int getNrColoane(){
        return n;
    }
    void setElement(int,int,T);

};

template <class T>
ostream &operator<<(ostream &os, matrice<T> &b){
    int i,j;
    for(i=0;i<b.m;i++){
        for(j=0;j<b.n;j++){
            os<<b.a[i][j]<<" ";
        }
        os<<endl;
    }
    return os;
}

template <class T>
matrice<double> operator+(matrice<double> &a,matrice<double> &b){
	matrice<double> c;
	c.m=a.m;
	c.n=a.n;
	c.a=new double*[m];
	for(int i=0;i<m;i++)c.a[i]=new double[n];
	for(int i=0;i<a.m;i++)
		for(int j=0;j<a.n;j++)c.a[i][j]=a.a[i][j]+b.a[i][j];
	return c;
}

matrice<char *>::matrice(int linii,int col):m(linii),n(col){
    int i,j;
    a=new char**[m];
    for(i=0;i<m;i++){a[i]=new char*[n];}
    for(i=0;i<m;i++)
        for(j=0;j<n;j++){
            cout<<"a["<<i<<"]["<<j<<"]= ";
            char *tmp;
            tmp=new char[100];
            cin>>tmp;
            a[i][j]=new char[strlen(tmp)+1];
            strcpy(a[i][j],tmp);
            delete tmp;
        }
}

matrice<double>::matrice(char *filename){
	FILE *f;
	f=fopen(filename,"r");
	fscanf(f,"%i %i\n",&m,&n);
	a=new double*[m];
	for(int i=0;i<m;i++)a[i]=new double[m];
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++)
			fscanf(f,"%lf ",&(a[i][j]));
		fscanf(f,"\n");
	}
}

//friend class Iterator;

void main (int argc, char * const argv[]) {
    //matrice<char *> m1(2,2);
	matrice<double> m1("matrice1.txt");
	matrice<double> m2("matrice2.txt");
    cout<<m1;
	cout<<endl;
	cout<<m2<<endl;

	matrice<double> m3;
	m3=m1+m2;

	cout<<m3;
    getch();
}

why r u using <double> now instead of <T>?

Because I want the operator function to work differently for double and for char (I want + to mean addtition for double and string concatenation for char*). Can't I define the behaviour of a method for a particular type?

Edited 5 Years Ago by arthurav: n/a

#include <iostream>

[b]// declare the template friend function first[/b]

template< typename T > struct matrice ;
template < typename T > 
std::ostream& operator<< ( std::ostream& stm, const matrice<T>& m ) ;

template< typename T > struct matrice
{
    //...

    [b]// add <> to the friend declaration in the class 
    // this tells the compiler that the friend function is a template[/b]

    friend std::ostream& operator<< [b]<>[/b] ( std::ostream& stm, const matrice& matrice ) ;

    // ...
};

// define the friend function normally

template < typename T > 
std::ostream& operator<< ( std::ostream& stm, const matrice<T>& m )
{
    // ...
    return stm ;
}

See: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16

This article has been dead for over six months. Start a new discussion instead.