简体   繁体   中英

Non template friend function of 2 templated classes undefined reference error

Problem Statement:

Using 2 different Templated classes 1 matrix class and other 1 vectorimp class and using 1 friend function which is multiply function.

Error Location

 multiply(matA,p);
in main.cpp 

Issue: As I am using non templated function with arugements as templated classes so I am getting error

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

Error:

**** 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 projects\Matrix_Vector_Multiplication\Debug/../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.  

matrix class with.h and.cpp file:

matrix.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);
  };

matrix.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.9fus\n",
               double(stop - start)/CLOCKS_PER_SEC);*/
  }
}

template class matrix<int>;

vector.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);
  };

vector.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>;

main.cpp file

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

To be honest I am not an expert in coding so getting confused in using templates. Thanks a lot for help in advance.

Disclaimer:

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 

There are two suggestions I would like to make, first of all, put your header and cpp files together as you are using template, Secondly please look at the following line of code:

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

You did nothing in the destructor this is dangerous, try adding in something like delete[] vec, Also from the line above:

vec = vec[4][4];

It looks like you are trying to intialize a 2D vector, but in your declaration:

int vec[3]

Dangerous.....

T vec3D[3][3];

Declaring this guy but you never intialized it with your constructor. then you called this guy:

vectorimp<int> p;

Which intializes your vec3D to nullptr. Finally you decided to pass this nullptr object to your method populate1D: and do the following call:

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

Which since vec is nullptr, program breaks.

You are defining multiply(matrix<int>, vectorimp<int>) in a cpp file, which is an independent compilation unit and thus, not seen outside that file. The templates are instantiated when used/needed, but if it is used in a different compilation unit, the compiler hasn't the function body so it is undefined. You have to put the function body in the header, so the function body is available for all compilation units ( cpp files) that need it.

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
}

You have to declare the friend function before the class matrix and/or class vectorimp , then tell the compiler it is a template function. You can't put the template<class T> in the friend declaration inside the class because it shadows the template parameter, so simply multiply<> (with angles.)

You have other errors, as not creating a coy constructor. multiply function will receive a copy of the matrix and vectorimp parameters; when the function returns the copies will be delete d and when the program ends you will have a double deletion.

If you pass parameters by reference there will by no double deletion.

In matrix::~matrix you have to delete mat to avoid memory leak.

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

You are allocating int s for an unknown type T :

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

This should be:

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

And you are mixing indexes with the template type:

T rows ;
T cols ;

Those are independent of the parameter type.

If you make those changes it will work without memory leaks:


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)

There are also lots of hard coded array indexes (value 3 ) in declarations and loops that will break if there are matrix and/or vector size changes in main .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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