weird undefined reference error when compiling multiple files [duplicate] - c++

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I am trying to code a toy program to exercise C++, but I got a weird undefined reference error that I can not solve.
My code consists of 3 file:
ex13_6.h:
#include<vector>
namespace ex13_6 {
template<class T> class Cmp {
public:
static int eq(T a, T b) {return a == b;}
static int lt(T a, T b) {return a < b;}
};
template<class T, class C = Cmp<T> > void bubble_sort(std::vector<T> &v);
}
ex13_6.cpp
#include<vector>
#include"ex13_6.h"
namespace ex13_6 {
template<class T, class C = Cmp<T> > void bubble_sort(std::vector<T> &v) {
int s = v.size();
T swap;
for (int i=0; i<s; i++) {
for (int j=0; j<s; j++) {
if (C::lt(v.at(j), v.at(i))) {
swap = v.at(i);
v.at(i) = v.at(j);
v.at(j) = swap;
}
}
}
}
}
main.cpp:
#include"ex13_6.h"
#include<iostream>
#include<vector>
using namespace std;
using namespace ex13_6;
int main() {
// Sort using default comparison for int
vector<int> v_int;
for (int i=0; i<10; i++) {
v_int.push_back(10-i);
}
bubble_sort(v_int);
cout << "sort of int vector:\n";
for (vector<int>::const_iterator it = v_int.begin(); it != v_int.end(); it++) {
cout << ' ' << *it;
}
cout << '\n';
}
And I am compiling using:
g++ main.cpp -o main -std=gnu++0x ex13_6.cpp
Here is the error message:
/tmp/ccRwO7Mf.o: In function `main':
main.cpp:(.text+0x5a): undefined reference to `void ex13_6::bubble_sort<int, ex13_6::Cmp<int> >(std::vector<int, std::allocator<int> >&)'
collect2: ld returned 1 exit status
I really appreciate any help!

Move your implementation of the bubble_sort template into your header file.
Templates are not like generics from Java, all the magic happens at compile time in C++. In order for the compiler to generate the code for each template instantiation, it must be visible, and to do that, it must be in the header (or some other file) and included in each translation unit that uses it.

Your templated function definition should be in the ex13_6.h file:
#include<vector>
namespace ex13_6 {
template<class T> class Cmp {
public:
static int eq(T a, T b) {return a == b;}
static int lt(T a, T b) {return a < b;}
};
template<class T, class C = Cmp<T> > void bubble_sort(std::vector<T> &v) {
int s = v.size();
T swap;
for (int i=0; i<s; i++) {
for (int j=0; j<s; j++) {
if (C::lt(v.at(j), v.at(i))) {
swap = v.at(i);
v.at(i) = v.at(j);
v.at(j) = swap;
}
}
}
}
}

You need to put the template implementation in the header file.
When instantiating a template the compiler needs to "see" the implementation, so if you just include the header, the implementation needs to be there.
Don't include a .cpp file.

Related

Vector declared in header file isn't being recognized C++

I have been having a lot of issues with header files, and now it seems that the vector that is declared in my header file, Polynomial.hpp, is not being recognized in Polynomial.cpp. I have already included std:: which seems to be a common mistake, so I don't know where to go from here.
Header file:
#ifndef POLYNOMIAL_HPP
#define POLYNOMIAL_HPP
#include<vector>
#include"term.hpp"
class Polynomial {
private:
std::vector<Term> vect;
public:
Polynomial();
~Polynomial();
void add(Term t);
void print();
Polynomial combineLikeTerms();
};
#endif
cpp File:
#include "term.hpp"
#include "Polynomial.hpp"
#include<iostream>
#include<map>
using namespace std;
void add(Term t) {
vect.push_back(t);
}
void print() {
for(int i = 0; i < vect.size(); i++) {
cout << vect[i].toString();
}
}
Polynomial combineLikeTerms() {
Polynomial poly;
map<int, int> combinedPoly;
for(int j = 0; j < vect.size(); j++)
{
combinedPoly.insert(pair<int, int>(vect[j].getExponent(), vect[j].getCoefficient());
}
for(map<int,int>::iterator itr = combinedPoly.begin(); itr != combinedPoly.end(); itr++) {
Term newTerm(itr->second, "x", itr->first);
poly.add(newTerm);
}
return poly;
}
Error (1/6):
Polynomial.cpp:9:5: error: use of undeclared identifier 'vect'
vect.push_back(t);
In Polynomial.cpp you are defining new functions instead of member functions. Change the definitions to use the class name like
void Polynomial::add(Term t) {
vect.push_back(t);
}
Your void add(Term T) in Polynomial.cpp is not the member function of the Polynomial.
You must implement this function as member of Polynomial like this
void Polynomial::add(Term T){
...
}
I think this is a syntax error. First, you defined the add method in the Polynomial class of the header file, but the CPP file did not add the class scope, which caused this problem. So you should adjust your code like this:
void Polynomial::add(Term t) {
vect.push_back(t);
}
The root cause of this problem is that the methods of the class only work within the scope of the class, and if there is a function with the same name inside the class, it will lead to a naming conflict. Therefore, the root cause of this problem is not the reference error of the vector file.
The issue is that instead of defining the members add and print of the class Polynomial, you are defining functions in global scope completely unrelated to the class Polynomial
Make changes in the function definition of void add(Term) and void print() to void Polynomial::add(Term) and void Polynomial::print().
#include "term.hpp"
#include "Polynomial.hpp"
#include<iostream>
#include<map>
using namespace std;
void Polynomial::add(Term t) { // change here
vect.push_back(t);
}
void Polynomial::print() { //change here
for(int i = 0; i < vect.size(); i++) {
cout << vect[i].toString();
}
}
Polynomial combineLikeTerms() {
Polynomial poly;
map<int, int> combinedPoly;
for(int j = 0; j < vect.size(); j++)
{
combinedPoly.insert(pair<int, int>(vect[j].getExponent(), vect[j].getCoefficient());
}
for(map<int,int>::iterator itr = combinedPoly.begin(); itr != combinedPoly.end(); itr++) {
Term newTerm(itr->second, "x", itr->first);
poly.add(newTerm);
}
return poly;
}

Unfamiliar use of "template" [duplicate]

This question already has answers here:
Explicit template instantiation - when is it used?
(4 answers)
Static table generation works with GCC but not clang; is clang bugged?
(1 answer)
Closed 1 year ago.
I was working with code from an answer to this question:
#include <iostream>
#include <string>
using std::cin;
using std::cout;
template<int N, int I=N-1>
class Table : public Table<N, I-1>
{
public:
static const int dummy;
};
template<int N>
class Table<N,0>
{
public:
static int array[N];
static const int dummy;
};
template<int N, int I>
const int Table<N,I>::dummy = Table<N,0>::array[I] = I + 0*Table<N,I-1>::dummy;
template<int N>
int Table<N,0>::array[N];
template<int N>
const int Table<N,0>::dummy = 0;
template class Table<5>; //<-what does this statement do? The program does not work without it.
int main()
{
std::string s;
int *array = Table<5,0>::array;
for(int i = 0; i < 5; i++)
{
cout << array[i] << " ";
}
cout << "\n";
cout << "Press ENTER to exit.\n";
std::getline(cin, s);
}
The line template class Table<5>; just before the start of the main routine is marked off with a comment in the listing and shows a use of the work "template" that I am not familiar with. What is the justification for this line of code?

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
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 deleted 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 ints 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.
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.

Why am I getting the error 'undefined reference to `MinHeap<char>::insert(char, int)`' [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 2 years ago.
I am currently trying to implement a min heap, however, I am running into an issue.
I am having difficulty determining why my code is not linking properly when I compile it. The files, commands, and error are as follows:
min_heap.h
#ifndef MIN_HEAP_H
#define MIN_HEAP_H
#include <vector>
#include <algorithm>
using namespace std;
template <typename T>
struct HeapNode {
HeapNode(const T data, const int key) : data(data), key(key) {}
bool operator<(const HeapNode<T>& rhs) {return this->key < rhs.key;}
bool operator<=(const HeapNode<T>& rhs) {return this->key <= rhs.key;}
T data;
int key;
};
template <typename T>
class MinHeap {
public:
MinHeap() {};
~MinHeap() {};
void insert(const T data, const int key);
T extract_min();
T peek() const;
int size() const;
private:
vector<HeapNode<T>> heap;
};
#endif
min_heap.cpp
#include <iostream>
#include "min_heap.h"
using namespace std;
template <typename T>
void MinHeap<T>::insert(const T data, const int key){
cout << "Insertion." << endl;
if(this->heap.size() == 0){
cout << "adding first node" << endl;
this->heap.push_back(new HeapNode<T>(data, key));
}else{
cout << "not first node." << endl;
this->heap.push_back(new HeapNode<T>(data, key));
int currentIndex = this->heap.size() - 1;
while(((currentIndex - 1) / 2) >= 0){
if(this->heap[(currentIndex - 1) / 2] > this->heap[currentIndex]){
swap(this->heap[currentIndex], this->heap[(currentIndex - 1) / 2]);
currentIndex = ((currentIndex - 1) / 2);
}else{
break;
}
}
}
}
template <typename T>
T MinHeap<T>::extract_min(){
T data;
data = NULL;
return data;
}
template<typename T>
T MinHeap<T>::peek() const{
T data;
if(this->heap.size() == 0){
cout << "size: 0" << endl;
data = NULL;
}else{
cout << "something in there" << endl;
data = this->heap[0];
}
return data;
}
template<typename T>
int MinHeap<T>::size() const {
return this->heap.size();
};
customMain.cpp
#include <iostream>
#include "min_heap.h"
using namespace std;
int main(){
MinHeap<char> heap = MinHeap<char>();
const char data = 'a';
const int key = 7;
heap.insert(data, key);
return 0;
}
I am compiling the files above with the following
g++ -c min_heap.cpp
g++ -c customMain.cpp
g++ min_heap.o customMain.o
The error:
customMain.o:customMain.cpp:(.text+0x41): undefined reference to `MinHeap<char>::insert(char, int)'
collect2.exe: error: ld returned 1 exit status
Any help would be greatly appreciated!
Two options.
1) Move the template implementations out of the cpp file, and put them in the header. The compiler, when compiling main.cpp, cannot see the code it needs to generate the specialisation for char, so you end up being left with an unresolved external. Moving the code to the header will solve the issue (almost all template code resides in header files)
2) You can export specialisations from the cpp file, but then the types are locked down in advance (i.e. you can only use the exported types), which kinda reduces the flexibility and whole point of using templates. That's why 99.99% of people choose option 1, 99.99% of the time.
// export specialisations for char, short, int, and float
template class MinHeap<char>;
template class MinHeap<short>;
template class MinHeap<int>;
template class MinHeap<float>;

Visual Studio error LINK1120

In VS 2013 , I declared a function in a header file named "util_serial.h" and defined it in the cpp file named "util_serial.cpp", like this:
util_serial.h :
#ifndef _UTIL_SERIAL_H_
#define _UTIL_SERIAL_H_
template<typename T> inline std::vector<T> slice_vec(std::vector<T>& vec, int _begin, int len);
#endif
util_serial.cpp :
#include "util_serial.h"
using namespace std;
template<typename T> inline std::vector<T> slice_vec(vector<T>& vec, int _begin, int len) {
if (_begin < 0) {
_begin = 0;
}
if (vec.size() < _begin) {
vector<T> v;
printf("slicing out of the vector range\n");
return v;
}
if (vec.size() < _begin + len) {
vector<T> v(vec.begin() + _begin, vec.end());
return v;
}
else {
vector<T> v(vec.begin() + _begin, vec.begin() + _begin + len);
return v;
}
}
Then I call this function in main function at another cpp file :
#include "util_serial.h"
using namespace std;
void main() {
vector<int> v3(4, 8);
vector<int> v4;
v4 = slice_vec(v3, 0, 2);
for (unsigned int i = 0; i < v4.size(); i++) {
cout << v4[i] << endl;
}
}
And then a LINK error occurred:
But when I define this function in the util_serial.h file right there after the declaration, this error disappeared.
This is what I used to do, declaring a function in a header file and putting its definition in another cpp file and it always works. But why this time it doesn't ?
That's how templates work. If you don't put the template function into the header file you need to explicitely instantiate the function for the type(s) that you need.
template std::vector<int> slice_vec<int>(std::vector<int>& vec, int _begin, int len);
See also How do I explicitly instantiate a template function?.