简体   繁体   English

关于在模板类中声明好友模板function的问题(C++)

[英]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).我们的老师说我们必须将“DisplayMatrix”设为全局 function 所以它必须是 class CMyMatrix 的朋友 function(如果我不想写更多的函数)。 But there is an exception like this.但也有这样的例外。
Code: LNK2019;代码:LNK2019; Description: unresolved external symbol "void _cdecl DisplayMatrix(class CMyMatrix)"(?DisplayMatrix@@YAXV?$CMyMatrix@H@@@Z) referenced in function _main;说明:在 function _main 中引用的未解析外部符号“void _cdecl DisplayMatrix(class CMyMatrix)”(?DisplayMatrix@@YAXV?$CMyMatrix@H@@@Z); Line 1; 1号线; File:CMyMatrix.obj文件: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.我注意到 class CMyMatrix 中的“DisplayMatrix”在我的 IDE 中没有改变颜色,所以我认为可能存在一些问题。 But I don't know how to solve it.但我不知道如何解决它。 I would appreciate it if someone could help me.如果有人可以帮助我,我将不胜感激。

The friend declaration declares a non-template function, which doesn't match the function template's definition in the global scope. friend元声明声明了一个非模板 function,它与全局 scope 中的 function 模板的定义不匹配。

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或将模板friend声明为

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;
            }
        }
    }
}

I would like to present an answer that is not really a solution.我想提出一个不是真正解决方案的答案。 The point of this non-solution is to expand upon why the solution works (I admit that this answer would be worth little without the answer provided by songyuanyao.) This might help clarify things for future readers, especially if certain comments ever disappear.这个非解决方案的重点是扩展解决方案的工作原理(我承认如果没有宋元瑶提供的答案,这个答案将毫无价值。)这可能有助于为未来的读者澄清事情,特别是如果某些评论消失了。

To start, here is a simplified setup, where I've removed some things extraneous to the question (cf minimal, reproducible example ):首先,这是一个简化的设置,其中我删除了一些与问题无关的内容(参见最小的、可重现的示例):

template<class T>
class CMyMatrix{
    friend void DisplayMatrix(CMyMatrix<T>);
};

template<class T>
void DisplayMatrix(CMyMatrix<T>) {
}

int main(){
    CMyMatrix<int> matrix;
    DisplayMatrix(matrix);
    return 0;
}

The problem is that the friend is declared as a (non-template) function, while the definition of DisplayMatrix is a function template.问题是friend被声明为(非模板)function,而DisplayMatrix的定义是function模板。 These do not match, so the compiler is left with two meanings for the identifier DisplayMatrix .这些不匹配,因此编译器为标识符DisplayMatrix留下了两种含义。 When figuring out which meaning to use for the line DisplayMatrix(matrix);当确定使用DisplayMatrix(matrix);行的含义时, the compiler prefers the non-template (which is declared, but never defined). ,编译器更喜欢非模板(已声明但从未定义)。

So the answer is to make your declaration and definition agree.所以答案是让你的声明和定义一致。 One way to do this – likely not the solution anyone is looking for, but a way to make the compiler happy – is to change the definition to no longer be a template.做到这一点的一种方法——可能不是任何人都在寻找的解决方案,而是一种让编译器满意的方法——是将定义更改为不再是模板。

void DisplayMatrix(CMyMatrix<int>) {
}

With this change, the code compiles.通过此更改,代码可以编译。 Well, it complies provided you stick to int as your template parameter.好吧,只要您坚持使用int作为模板参数,它就符合要求。 So not really a solution, but a demonstration of what the friend declaration actually declares.所以不是真正的解决方案,而是friend声明实际声明的演示。 The real solution is to keep the (template) definition of DisplayMatrix and adjust the friend declaration, as in the accepted answer.真正的解决方案是保留DisplayMatrix的(模板)定义并调整friend声明,如接受的答案所示。


It might be interesting to note that gcc (but apparently not clang?) has a warning applicable to this situation.有趣的是,gcc(但显然不是 clang?)有适用于这种情况的警告。

 warning: friend declaration 'void DisplayMatrix(CMyMatrix<T>)' declares a non-template function [-Wnon-template-friend] friend void DisplayMatrix(CMyMatrix<T> matrix); ^ note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM