0
votes

I am trying to define a matrix class with simple operations. To be compitable with int, float, double data type, I use the template. And I overload the "<<" operator to print the matrix. How ever, when I compile the program, I get a LNK2019 error.

Error 2 error LNK1120: 1 unresolved externals
Error 1 error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class Mat const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$Mat@H@@@Z) referenced in function _main

I have tried to find the error and just could not figure out the problem.

Here is the detail: system infromation: windows 10 x64, visual studio 2013

mat.h file

#ifndef _MAT_H_
#define _MAT_H_

#include <iostream>
#include <ostream>
#include <sstream>
#include <vector>
#include <cstring>
#include <cassert>

//implement Mat class in c++


template<typename T>
class Mat{

friend  std::ostream& operator<<(std::ostream &os, const Mat<T> &m);
friend  std::istream& operator>>(std::istream &is, Mat<T> &m);

public:

//construct
Mat();
Mat(size_t i, size_t j);

//destructor
~Mat();

//access element value
T& MatVale(size_t i, size_t j);
const T& MatVale(size_t i, size_t j) const;

//get row and col number
const size_t rows() const{ return row; }
const size_t cols() const{ return col; }

private:

size_t row;
size_t col;
T* pdata;
};

#endif

mat.cpp file

`
#include "mat.h"

using std::cout;
using std::endl;
using std::istream;
using std::ostream;

template<typename T>
ostream& operator<<(ostream &os, const Mat<T>&m){
    for (int i = 0; i < m.row; i++){
        for (int j = 0; j < m.col; j++){
            os << m.pdata[i*m.col + j] << " ";
        }
        os << std::endl;
    }
    os << std::endl;
    return os;
}

template<typename T>
istream& operator>>(istream &is, Mat<T>&m){
    for (int i = 0; i < m.row; i++){
        for (int j = 0; j < m.col; j++){
            is >> m.pdata[i*m.col + j];
        }
    }
    return is;
}

//construct
template<typename T>
Mat<T>::Mat(){
    cout << "defalut constructor" << endl;
    row = 0;
    col = 0;
    pdata = 0;
}

template<typename T>
Mat<T>::Mat(size_t i, size_t j){
    row = i; col = j;
    pdata = new T[row*col];
    std::memset(pdata, 0, row*col*sizeof(T));
}

//destructor
template<typename T>
Mat<T>::~Mat(){
    if (pdata) delete[] pdata;
}

//access element value
template<typename T>
inline T& Mat<T>::MatVale(size_t i, size_t j){
    assert(pdata && i>=0 && j>=0 && i < row && j < col);
    return pdata[i*col + j];
}

template<typename T>
inline const T& Mat<T>::MatVale(size_t i, size_t j) const{
    assert(pdata && i >= 0 && j >= 0 && i < row && j < col);
    return pdata[i*col + j];
}

int main(){

    Mat<int> mat1(7, 2);
    Mat<int> mat2(7, 2);

    for (size_t i = 0; i < mat1.rows(); i++){
        for (size_t j = 0; j < mat1.cols(); j++){
            mat1.MatVale(i, j) = i + j+3;
            mat2.MatVale(i, j) = 2 * i + j+11;
        }
    }
    std::cout << mat1;//comment this line then it is okay.
    return 1; 
}
1
I know how to solve this problem now. en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Making_New_FriendsYan
and I summarized several methods to solve this problem. see here: blog.csdn.net/yc461515457/article/details/51240348Yan

1 Answers

0
votes

in fact, you can use a member function to do print job and define a non-member non-friend function which calling this member function. SO that you can void using friend function in a template class.

something like this:

//non-member and non-feriend overload function
template<typename T>
std::ostream& operator<<(std::ostream& os, const Mat<T>& m){
    m.CoutMat(os);//call member function
    return os;
}

and in the class definition, you have a member function to do print job.

 //member function to do print job
void CoutMat(std::ostream& os) const;