关于在模板中声明友元模板函数的问题class(C++)
A question about declaring a friend template function in a template class(C++)
我正在编写实现矩阵某些功能的作业。这是为了解决问题的简化版本。
#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;
}
我们的老师说我们必须让"DisplayMatrix"成为一个全局函数所以它必须是class CMyMatrix 的友元函数(如果我不想写更多的函数)。但是有这样一个例外。
代码:LNK2019;说明:未解析的外部符号 "void _cdecl DisplayMatrix(class CMyMatrix)"(?DisplayMatrix@@YAXV?$CMyMatrix@H@@@Z) 在函数 _main 中引用; 1号线;
File:CMyMatrix.obj
我注意到 class CMyMatrix 中的 "DisplayMatrix" 在我的 IDE 中没有改变颜色,所以我认为可能存在一些问题。但我不知道如何解决。如果有人能帮助我,我将不胜感激。
friend
声明声明了一个非模板函数,它在全局范围内与函数模板的定义不匹配。
你可以
// 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;
}
}
}
}
或将模板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;
}
}
}
}
我想提出一个并非真正解决方案的答案。这个非解决方案的重点是扩展为什么 有效(我承认如果没有 songyuanyao 提供的答案,这个答案将毫无价值。)这可能有助于为未来的读者澄清事情,特别是如果某些评论曾经消失。
首先,这是一个简化的设置,其中我删除了一些与问题无关的内容 (c.f。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;
}
问题是 friend
被声明为一个(非模板)函数,而 DisplayMatrix
的定义是一个函数模板。这些不匹配,因此编译器为标识符 DisplayMatrix
留下了两种含义。在确定行 DisplayMatrix(matrix);
的含义时,编译器更喜欢非模板(已声明,但从未定义)。
所以答案就是让你的声明和定义一致。一种方法(可能不是任何人正在寻找的解决方案,而是一种让编译器满意的方法)是将定义更改为不再是模板。
void DisplayMatrix(CMyMatrix<int>) {
}
通过此更改,代码可以编译。好吧,只要您坚持使用 int
作为模板参数,它就符合要求。所以这不是一个真正的解决方案,而是 friend
声明实际声明的演示。真正的解决方案是保留 DisplayMatrix
的(模板)定义并调整 friend
声明,如已接受的答案。
有趣的是,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)
我正在编写实现矩阵某些功能的作业。这是为了解决问题的简化版本。
#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;
}
我们的老师说我们必须让"DisplayMatrix"成为一个全局函数所以它必须是class CMyMatrix 的友元函数(如果我不想写更多的函数)。但是有这样一个例外。
代码:LNK2019;说明:未解析的外部符号 "void _cdecl DisplayMatrix(class CMyMatrix)"(?DisplayMatrix@@YAXV?$CMyMatrix@H@@@Z) 在函数 _main 中引用; 1号线;
File:CMyMatrix.obj
我注意到 class CMyMatrix 中的 "DisplayMatrix" 在我的 IDE 中没有改变颜色,所以我认为可能存在一些问题。但我不知道如何解决。如果有人能帮助我,我将不胜感激。
friend
声明声明了一个非模板函数,它在全局范围内与函数模板的定义不匹配。
你可以
// 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;
}
}
}
}
或将模板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;
}
}
}
}
我想提出一个并非真正解决方案的答案。这个非解决方案的重点是扩展为什么
首先,这是一个简化的设置,其中我删除了一些与问题无关的内容 (c.f。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;
}
问题是 friend
被声明为一个(非模板)函数,而 DisplayMatrix
的定义是一个函数模板。这些不匹配,因此编译器为标识符 DisplayMatrix
留下了两种含义。在确定行 DisplayMatrix(matrix);
的含义时,编译器更喜欢非模板(已声明,但从未定义)。
所以答案就是让你的声明和定义一致。一种方法(可能不是任何人正在寻找的解决方案,而是一种让编译器满意的方法)是将定义更改为不再是模板。
void DisplayMatrix(CMyMatrix<int>) {
}
通过此更改,代码可以编译。好吧,只要您坚持使用 int
作为模板参数,它就符合要求。所以这不是一个真正的解决方案,而是 friend
声明实际声明的演示。真正的解决方案是保留 DisplayMatrix
的(模板)定义并调整 friend
声明,如已接受的答案。
有趣的是,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)