Search code examples
c++templatesfriend

A question about declaring a friend template function in a template class(C++)


I'm writing my assignment that implements some functions of matrix. Here is a simplified version in order to fix on the problem.

#include <iostream>
using namespace std;

template<class T>
class CMyMatrix{
private:
    int row;
    int col;
    T** elements;
public:
    CMyMatrix(int row, int col);
    void SetMatrix(T* data, int row, int col);
    friend void DisplayMatrix(CMyMatrix<T> matrix);
};

template<class T>
CMyMatrix<T>::CMyMatrix(int row,int col) {
    this->row = row;
    this->col = col;
    this->elements = new T* [row];
    for (int i = 0;i < row;i++) {
        this->elements[i] = new T[col];
    }
}

template<class T>
void CMyMatrix<T>::SetMatrix(T* data, int row, int col) {
    this->row = row;
    this->col = col;
    if (elements != 0) delete[]elements;
    this->elements = new T* [row];
    for (int i = 0;i < row;i++) {
        this->elements[i] = new T[col];
    }
    for (int i = 0;i < row * col;i++) {
        elements[i / col][i % col] = data[i];
    }
}


template<class T>
void DisplayMatrix(CMyMatrix<T> matrix) {
    for (int i = 0;i < matrix.row;i++) {
        for (int j = 0;j < matrix.col;j++) {
            cout << matrix.elements[i][j] << " ";
            if (j == matrix.col - 1) {
                cout << endl;
            }
        }
    }
}

int main(){
    CMyMatrix<int> matrix(2, 3); 
    int a[6] = {1, 2, 3, 4, 5, 6};
    matrix.SetMatrix(a, 2, 3);
    DisplayMatrix(matrix);
    return 0;
}

Our teacher said we have to make "DisplayMatrix" a global function so it has to be a friend function of class CMyMatrix(If I don't want to write more functions). But there is an exception like this.
Code: LNK2019; Description: unresolved external symbol "void _cdecl DisplayMatrix(class CMyMatrix)"(?DisplayMatrix@@YAXV?$CMyMatrix@H@@@Z) referenced in function _main; Line 1; File:CMyMatrix.obj

I notice that the "DisplayMatrix" in class CMyMatrix don't change color in my IDE, so I think there might be some problems. But I don't know how to solve it. I would appreciate it if someone could help me.


Solution

  • The friend declaration declares a non-template function, which doesn't match the function template's definition in the global scope.

    You could

    // forward declaration
    template<class T>
    class CMyMatrix;
    
    // declaration
    template<class T>
    void DisplayMatrix(CMyMatrix<T> matrix);
    
    template<class T>
    class CMyMatrix{
    private:
        int row;
        int col;
        T** elements;
    public:
        CMyMatrix(int row, int col);
        void SetMatrix(T* data, int row, int col);
        // friend declaration; refering to the function template
        friend void DisplayMatrix<T>(CMyMatrix<T> matrix);
        //                       ^^^
    };
    
    ...
    
    // definition
    template<class T>
    void DisplayMatrix(CMyMatrix<T> matrix) {
        for (int i = 0;i < matrix.row;i++) {
            for (int j = 0;j < matrix.col;j++) {
                cout << matrix.elements[i][j] << " ";
                if (j == matrix.col - 1) {
                    cout << endl;
                }
            }
        }
    }
    

    Or declare template friend as

    template<class T>
    class CMyMatrix{
    private:
        int row;
        int col;
        T** elements;
    public:
        CMyMatrix(int row, int col);
        void SetMatrix(T* data, int row, int col);
        // declares template friend;
        // note that all the instantiations of DisplayMatrix become friend
        template <class X>
        friend void DisplayMatrix(CMyMatrix<X> matrix);
    };
    
    ...
    
    template<class T>
    void DisplayMatrix(CMyMatrix<T> matrix) {
        for (int i = 0;i < matrix.row;i++) {
            for (int j = 0;j < matrix.col;j++) {
                cout << matrix.elements[i][j] << " ";
                if (j == matrix.col - 1) {
                    cout << endl;
                }
            }
        }
    }