Search code examples
c++classtemplatesfriend

Error happens when use friend function to manipulate private variables in template class in C++


I am writing a matrix operation library recently.And I want to overload operator s in my program, but Error happened when I use friend function to access private variables in the template class I was defined. (And it reports error only when I overload the operator '+', and the overload function of operation '-' doesn't report error.) the template class I defined is below:

template<class T>
class Matrix
{
    int col;
    int row;
    T *matrix;
    public:
        Matrix(T *m, int row1, int col1):matrix(m), row(row1), col(col1){}
        Matrix(int row1, int col1):row(row1), col(col1)
        {
            matrix = new T[row*col];
            cout<<"Have set the shape of the matrix, but should use create() to initialize the matrix!"<<endl;
        }
        Matrix(){}
        ~Matrix(){}
        void show();
        UINT create(T *m);
        UINT zeros(int size);
        UINT eye(int size);

        // the overload function statement
        friend Matrix operator+(const Matrix &a, const Matrix &b);
        friend Matrix operator-(const Matrix &a, const Matrix &b);

        Matrix matrix_T();              // transpose the matrix
        Matrix matrix_Inv();            // calculate matrix's inverse
        Matrix matrix_Adjoint();        // calculate the adjoint matrix
};

And the defination of this two overload functions are below:

// report error: can't access private member declared in class
template<class T>
Matrix<T> operator +(const Matrix<T> &m1, const Matrix<T> &m2)
{
    if (m1.col!=m2.col || m1.row!=m2.row)
    {
        cout<<"These two matrices can't be plused!"<<endl;
        exit(0);
    }
    T *tmp = new T[m1.col*m1.row];
    for (int i=0; i<m1.row; i++)
    {
        for (int j=0; j<m1.col; j++)
        {
            tmp[i*m1.col+j] = m1.matrix[i*m1.col+j] + m2.matrix[i*m1.col+j];
        }
    }
    return Matrix<T>(tmp, m1.row, m1.col);
}


// this defination didn't report error
// and if I only run this code, there is nothing wrong
template<class T>
Matrix<T> operator -(const Matrix<T> &m1, const Matrix<T> &m2)
{
    if (m1.col!=m2.col || m1.row!=m2.row)
    {
        cout<<"These two matrices can't be plused!"<<endl;
        exit(0);
    }
    T *tmp = new T[m1.col*m1.row];
    for (int i=0; i<m1.row; i++)
    {
        for (int j=0; j<m1.col; j++)
        {
            tmp[i*m1.col+j] = m1.matrix[i*m1.col+j] - m2.matrix[i*m1.col+j];
        }
    }
    return Matrix<T>(tmp, m1.row, m1.col);
}

I've tested these two pieces of code seperately, the overload of operator '-' can be compiled correctly, but operator '+' can't. The error imformations are below:

f:\program\c++\matrixoperate\matrixdefine.h(134) : error C2248: 'col' : cannot access private member declared in class 'Matrix<int>'
    f:\program\c++\matrixoperate\matrixdefine.h(6) : see declaration of 'col'
    f:\program\c++\matrixoperate\demo.cpp(14) : see reference to function template instantiation 'class Matrix<int> __cdecl operator +(const class Matrix<int> &,const class Matrix<int> &)' being compiled
f:\program\c++\matrixoperate\matrixdefine.h(134) : error C2248: 'col' : cannot access private member declared in class 'Matrix<int>'
    f:\program\c++\matrixoperate\matrixdefine.h(6) : see declaration of 'col'

And the IDE I use is VC++6.0.


Solution

  • friend Matrix operator+(const Matrix &a, const Matrix &b); is not a template. It is a non template friend function of a template class.

    template<class T>Matrix<T> operator +(const Matrix<T> &m1, const Matrix<T> &m2) is a template. They are not the same function, as one is a template the other is not.

    The easiest way to fix this is to put the body inline in the template class definition.

    The second easiest way is to forward from operator+ to some static method, or some named function template. Forward declare it before the template class definition, friend it in the template class definition, implement it afterwarss.

    (You actually want operator+ to be a non-template friend of a template class, as that makes it play much nicer with conversions.)

    So do https://stackoverflow.com/a/13464246/1774667 but for a named function, not an operator. Call it add.

    Then friend Matrix operator+(const Matrix &a, const Matrix &b){ return add(a,b); } which gives you the non-template friend operator of template class magic.