2个模板化类的非模板友元函数未定义引用错误

Non template friend function of 2 templated classes undefined reference error

本文关键字:函数 未定义 错误 友元 引用 2个      更新时间:2023-10-16

问题陈述:

使用 2 个不同的模板化类 1 矩阵类和其他 1 个 vectorimp 类,并使用 1 个友元函数,即乘法函数。

错误位置

multiply(matA,p);
in main.cpp 

问题: 由于我使用非模板化函数作为模板化类,所以我得到错误

undefined reference to `multiply(matrix<int>, vectorimp<int>)'
collect2.exe: error: ld returned 1 exit status

错误:

**** Build of configuration Debug for project Matrix_Vector_Multiplication ****
**** Internal Builder is used for build               ****
g++ -oMatrix_Vector_Multiplication.exe Vector.o Matrix_Vector_Multiplication_main.o Matrix_Vector_Multiplication.o
Matrix_Vector_Multiplication_main.o: In function `main':
D:C++ Eclipse projectsMatrix_Vector_MultiplicationDebug/../Matrix_Vector_Multiplication_main.cpp:25: undefined reference to `multiply(matrix<int>, vectorimp<int>)'
collect2.exe: error: ld returned 1 exit status
Build error occurred, build is stopped
Time consumed: 1741  ms.  

带有 .h 和 .cpp 文件的矩阵类:

矩阵.h

#pragma once
#include <iostream>
#include<vector>
#include <time.h>
#include <ostream>
#include "Vector.h"
#define LENGTH 3
#define WIDTH  3
//using namespace std;
template <typename T>
class vectorimp;
template <typename T>
class matrix
{
private:
T rows ;
T cols ;
T g[LENGTH];
T **mat;
public:
//Default constructor
matrix(T rows , T cols);
~matrix();
T **generatematrix(int rows, int cols);
void populatematrix(T *src, T size);
void print();
template<class T>
friend void multiply(matrix<T> p, vectorimp<T> v);
};

矩阵.cpp

#include "Matrix_Vector_Multiplication.h"
#include <omp.h>
#include  <stdio.h>
#include <iostream>

using namespace std;
template <class T>
matrix<T>::matrix (T rows , T cols) : rows(rows),cols(cols) {
this ->mat = generatematrix(this ->rows ,this ->cols );
}
template <class T>
matrix<T>::~matrix()
{
for(int i=0; i< this->rows; i++)
{
delete[] this ->mat[i];
}
}
template <class T>
T **matrix<T> ::generatematrix (int rows, int cols){
T **temp = new int*[rows];
for(int i =0; i< rows; i++)
{
temp[i] = new int[cols];
}
return temp;
}
template <class T>
void matrix<T> ::print()
{
for(int i=0;i<rows;i++)
{
for(int j =0; j<cols; j++)
{
std::cout<<mat[i][j]<<" ";
}
cout<<endl;
}
}
template <class T>
void matrix<T>::populatematrix(T *src, T size)
{
if (rows * cols !=size){
cout<<"size of matrix is not equal to size of array"<< endl;
exit(-1);
}
int pos =0;
for(int i=0;i<rows; i++){
for(int j=0;j<cols; j++){
this->mat[i][j]=src[pos++];
}
}
}
template <class T>
void multiply (matrix<T> p, vectorimp<T> v)
{
#pragma omp parallel
int g[3];
for (int i=0;i<3;i++){
g[i]=0;
}
//multiplication.
//  clock_t start = clock();
#pragma omp for
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
// std::cout << "I am here "<< (v.vec[i][j])<<std::endl;
g[i] = g[i]+( p.mat[i][j] * v.vec[j]);
}
std::cout << "I am here "<< g[i]<<std::endl;
/*  clock_t stop = clock();
printf("Computing time = %0.9fusn",
double(stop - start)/CLOCKS_PER_SEC);*/
}
}
template class matrix<int>;

矢量.h

#pragma once
#include <iostream>
#include<vector>
#include <time.h>
#include <ostream>
#include "Matrix_Vector_Multiplication.h"
template <typename T>
class matrix;
template <typename T>
class vectorimp
{
private:
int vec[3];
T vec3D[3][3];
T size;
T recent;
public:
//Default constructor
vectorimp();
// Destructor
~vectorimp();
// function to get assign desired values to the vector
void populate_vector1D(std::vector <std::vector<T> > &data);
template<class T>
friend void multiply(matrix<T> p, vectorimp<T> v);
};

矢量.cpp

#include "Vector.h"
#include <iostream>
using namespace std;
template <class T>
vectorimp<T>::vectorimp(){
//vec = vec[4][4];
size = 1;
recent =0;
}
template <class T>
vectorimp<T>::~vectorimp(){}
template <class T>
void vectorimp<T>::populate_vector1D(std::vector <std::vector<T> > &data)
{
for (unsigned int i = 0; i < data.size(); i++)
{ // printing the 2D vector.
for (unsigned int j = 0; j < data[i].size(); j++)
{
vec[i]   = data[i][j];
}
}
}
template class vectorimp <int>;

主.cpp文件

#include "Matrix_Vector_Multiplication.h"
#include <iostream>
#include "Vector.h"
using namespace std;
int main()
{
int srcA[]= {2,4,3,1,5,7,0,2,3};
matrix<int> matA(3,3);
matA.populatematrix (srcA,9);
std::vector<std::vector<int> > v{ { 2,4,3 },
{ 5,1,6 },
{ 6,3,2 } };
vectorimp<int> p;
p.populate_vector1D(v);
multiply(matA,p);
return 0;
}

老实说,我不是编码专家,所以在使用模板时感到困惑。非常感谢提前提供的帮助。

免責聲明:

Checked out the avaiable resources  like 
https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl
https://stackoverflow.com/questions/1353973/c-template-linking-error
https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file?rq=1
and few more 

您正在cpp文件中定义multiply(matrix<int>, vectorimp<int>),该文件是一个独立的编译单元,因此在该文件之外看不到。模板在使用/需要时实例化,但如果在不同的编译单元中使用模板,编译器没有函数体,因此它是未定义的。 您必须将函数体放在标头中,以便函数体可用于所有需要它的编译单元(cpp文件(。

template <class T>
void multiply (matrix<T> p, vectorimp<T> v);
template <typename T>
class matrix
{
public:
friend void multiply<>(matrix<T> p, vectorimp<T> v);
};
template <class T>
void multiply (matrix<T> p, vectorimp<T> v)
{
// whatever
}

你必须在class matrix和/或class vectorimp之前声明friend函数,然后告诉编译器它是一个模板函数。您不能将template<class T>放在class内的 friend 声明中,因为它会隐藏模板参数,因此只需multiply<>(带角度(。

您还有其他错误,例如未创建 coy 构造函数。multiply函数将接收matrixvectorimp参数的副本;当函数返回时,副本将deleteD,当程序结束时,您将有双重删除。

如果通过引用传递参数,则不会重复删除。

matrix::~matrix您必须删除mat以避免内存泄漏。

for (int i=0; i < this->cols; i++)
{
delete [] this->mat[i];
}
delete [] this->mat;

您正在为未知类型分配intT

T **temp = new int*[rows];

这应该是:

T **temp = new T*[rows];

并且您正在将索引与模板类型混合在一起:

T rows ;
T cols ;

这些与参数类型无关。

如果您进行这些更改,它将在没有内存泄漏的情况下工作:


manuel@desktop:~/projects$ g++ -Wall main.cc -o main -std=c++17 && valgrind --leak-check=full ./main
==16701== Memcheck, a memory error detector
==16701== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16701== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==16701== Command: ./main
==16701== 
I am here 36
I am here 47
I am here 18
==16701== 
==16701== HEAP SUMMARY:
==16701==     in use at exit: 0 bytes in 0 blocks
==16701==   total heap usage: 13 allocs, 13 frees, 73,932 bytes allocated
==16701== 
==16701== All heap blocks were freed -- no leaks are possible
==16701== 
==16701== For counts of detected and suppressed errors, rerun with: -v
==16701== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

声明和循环中也有许多硬编码的数组索引(值3(,如果main中存在matrix和/或vector大小更改,这些索引将中断。

我想提出两个建议,首先,在使用模板时将您的头文件和 cpp 文件放在一起,其次请查看以下代码行:

vectorimp<T>::~vectorimp(){}

你在析构函数中什么也没做,这很危险,尝试添加类似 delete[] vec 的东西,也来自上面的行:

vec = vec[4][4];

看起来您正在尝试初始化 2D 向量,但在您的声明中:

int vec[3]

危险。。。。。

T vec3D[3][3];

声明这个家伙,但你从来没有用你的构造函数初始化它。 然后你打电话给这个人:

vectorimp<int> p;

这会将您的 vec3D 初始化为 nullptr。 最后,您决定将此 nullptr 对象传递给您的方法 populate1D: 并执行以下调用:

vec[i] = data[i][j]

由于 vec 是空点,程序中断。