redefinition of template<class T> in C++ - c++

I have searched and searched for a solution to my problem but I cannot seem to find one. I am using Code::Blocks and I am getting a redefinition error of a template class.
Here is my "vectorAux.h" file:
#ifndef vectoraux_h
#define vectoraux_h
#include <vector>
#include <algorithm>
#include <iostream>
template <typename T>
void removeDup(std::vector<T> & v);
template <typename T>
unsigned seqVectSearch(const std::vector<T> & v, unsigned first,
unsigned last, const T& target);
template <typename T>
void writeVector(const std::vector<T> & v);
#include "vectorAux.cpp"
#endif
and here is my "vectorAux.cpp" file:
#include "vectorAux.h"
#include <vector>
#include <algorithm>
#include <iostream>
template <typename T>
void removeDup(std::vector<T> & v)
{
std::vector<int> vector1;
unsigned i, last = v.size();
for(int j = 0; j <= v.size(); j++)
{
std::cout << seqVectSearch(v, j, last, j);
if(seqVectSearch(v, j, last, j) != v[i])
vector1.push_back(seqVectSearch(v, j, last, j));
}
}
template <typename T>
unsigned seqVectSearch(const std::vector<T> & v, unsigned first,
unsigned last, const T& target)
{
unsigned i = first;
while((v[i] != target) && (v[i] <= last))
{
if(v[i] == target)
return i;
i++;
}
return last;
}
template <typename T>
void writeVector(const std::vector<T> & v)
{
unsigned i;
unsigned n = v.size();
for (i = 0; i < n; i++)
std::cout << v[i] << ' ';
std::cout << std::endl;
}
the final file for this program is "vectorDriver.cpp" but this one has no errors. This one just runs the program by calling the functions:
#include "vectorAux.h"
#include <vector>
#include <iostream>
void fillVector(std::vector<int> & vect);
int main()
{
using namespace std;
vector<int> vect;
fillVector(vect);
cout << "Testing removeDup" << endl;
cout << "Original vector is ";
writeVector(vect);
removeDup(vect);
cout << "Vector with duplicates removed is ";
writeVector(vect);
cout << endl;
writeVector(vect);
return 0;
}
void fillVector(std::vector<int> & vect)
{
int arr[] = {1,7,2,7,9,1,2,8,9};
unsigned arrsize = sizeof(arr)/sizeof(int);
vect = std::vector<int>(arr, arr+arrsize);
}
I would really appreciate any and all help/advice that is given! I have looked around for a while and each source that I have found has said to guard the header file, but I have already done that and my problem still ensues.

You include vectorAux.cpp in vectorAux.h. I would guess that you are also compiling vectorAux.cpp separately. So you end up compiling the code in vectorAux.cpp twice.
Answer is simple, move the code from vectorAux.cpp to vectorAux.h, delete vectorAux.cpp, you don't need it.
Template code almost always goes in header files.

The contents of your "VectorAux.cpp" should be inside the "VectorAux.h" because you define a template class.

The simple answer is: Templates should not be split into source and header files. Keep it all in the header file when using templates.

Remove your .cpp of your templated class from your project source files. You are currently compiling the .cpp file twice; once because it is in your project and secondly because your .h is including it. Also, remove the .h inclusion from your .cpp, you don't need it since the header is including the .cpp at the bottom. This is one of the unfortunate problems of separating out templated classes.

The error happens during the compilation of the vectorAux.cpp file, because you are including the header file, which in turn includes the implementation file. This way, you end up with the content of the cpp file being duplicated.
If you really do want to split the implementation and declaration of the template functions into two separate files, there are two things you should do:
Don't include the headerfile in the implementation file.
Don't add the cpp file to the files being translated by the compiler.
Any one of those two options will get rid of your compiler error, but you really should do both.

Related

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?.

include guards not working

I've defined a util.h file with functions that i want to use throughout several different other files. This header has an include guard, however when i use it in two different files, I get a multiple definition of... error. What am i doing wrong?
I've read this but this pertains to variable declaration/definition. This answer seems more relevant but it's not clear to me how i can fix this.
// util.h
// include lots of standard headers
#include ...
#ifndef UTIL_H
#define UTIL_H
using namespace std;
// multiple definition of `randarr(int, int, int)`
int* randarr(int size, int min, int max) {
int *ret = new int[size];
for (int i=0; i<size; i++)
ret[i] = (int) (((double) rand() / RAND_MAX) * max) + min;
return ret;
}
// no error
template<typename T> void printarr(T* v, int begin, int end) {
for (int i=begin; i<end; i++)
cout << v[i] << " ";
cout << endl;
}
// multiple definition of `is_prime(int)`
bool is_prime(int n) {
if (n == 2 || n == 3 || n == 5) return true;
if (n <= 1 || (n&1) == 0) return false;
for (int i = 3; i*i <= n; i += 2)
if (n % i == 0) return false;
return true;
}
#endif
// example.cpp
#include ...// lots of standard includes
#include "util.h"
void f() {
randarr(...);
printarr(...);
is_prime(...);
...
}
// Main.cpp
#include "util.h"
int main() {
}
The include guards are not the cause of the error; you're violating the One Definition Rule. Since util.h is being included in 2 source files, the translation units created after preprocessing each source file will contain a definition of each of the functions, thus leading to the multiple definition error.
To get rid of the error, mark the functions inline
inline int* randarr(int size, int min, int max) {
// ...
}
template<typename T>
inline void printarr(T* v, int begin, int end) {
// ...
}
inline bool is_prime(int n) {
// ...
}
You are getting a linker error, not a compiler error. You have implemented the function randarr() in your util.h file, which means the compiler sees a copy of randarr() in each of example.cpp and Main.cpp. When the linker goes to link these together, it complains because you're not permitted to have more than one definition of the same function.
You have two choices:
declare randarr() as inline in the header file
move the definition for randarr() to a util.cpp file
Apply the same fix to is_prime().
You defined functions in a header file. This means, the code for these functions are included in both example.cpp and in Main.cpp. And it also means the code will be generated twice. This is the reason for the "multiple definition" error.
When you define the functions randarr() and is_prime() only once in a separate util.cpp, the errors will be gone.
Your header should only contain the prototype of your function. A prototype describes your function to other files, but do not implement it. The only exception is the template, because each template specialisation is build upon compile time.
If you implement your function in your header file, at linker time, you will find multiple times the function content, and that is why you are facing an error.
Move the implementation of randarr and is_prime to another file, and transform you util.h to :
#ifndef UTIL_H
#define UTIL_H
using namespace std;
int* randarr(int size, int min, int max);
template<typename T> void printarr(T* v, int begin, int end) {
for (int i=begin; i<end; i++)
cout << v[i] << " ";
cout << endl;
}
bool is_prime(int n);
#endif

Template and vector errors

I dont know what im doing wrong this is my first time seperating .cpp files and using templates and vectors. I keep getting these two errors: error C2143: syntax error : missing ',' before '<' and error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
main.cpp
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
void write_vector(const vector<T>& V);
int main()
{
int n;
int value;
vector<int> V;
cout << "Enter n: ";
cin >> n;
cout << "Enter " << n << " integer values: ";
while(V.size() < n && cin >> value){
V.push_back(value);
}
write_vector(V);
return 0;
}
writeVector.cpp
template <typename T>
void write_vector(const vector<T> &V)
{
for(int i=0; i < V.size(); i++)
cout << V[i] << " ";
}
You need explicit instantiation to do this because the compiler doesn't know what types the template needs to be compiled for when compiling the .cpp. See Explicit instantiation - when is it used?.
Your template function must be defined in advance so that the compiler can use it. Either define it before main() in the single file or #include it in a header file.
In summary, template functions should be defined in header files. See the answer to Why can templates only be implemented in the header file?
As far as I remember you cannot separate the declaration and implementation of a template.
You need the includes and using in both files. At that point, you might need the explicit instantiation mentioned in other answers, but those will show up as linker issues.
write_vector needs to be in a header file (writeVector.h) rather than a .cpp file if you want to share it between different modules. For more information about why you need to do this see the C++ FAQ.
I presume that your syntax error is because you have a missing using namespace std; in writeVector.cpp? When you move it to a header file you should not put this using directive there because that will needlessly pollute the global namespace whenever this file is included. Instead you should explicitly qualify all references to vector as std::vector.
On the top of you main.cpp add :
#include "Vector.cpp" // since you are learning, this is really strange and should be avoided, but for your example we leave it as is.
In your Vector.cpp
#include <vector>
#include <iostream>
template<class T>
void write_vector(const std::vector<T>& V)
{
for(int i=0; i < V.size(); i++)
std::cout << V[i] << " ";
}
Do not use using statements. Bad habit. You don't need explicit instantiation or other stuff. Your compiler can deduct the correct template.
Altough this works, it's bad code. When using template always write everything in the .h file. So change your Vector.cpp to Vector.h. Remove the forward declaration from your main.cpp and #include "Vector.cpp"
Your code will work fine without any other changes.
Finally the C++ way of doing things would be e.g. :
#include <vector>
#include <iostream>
#include <algorithm>
template<class T>
void write_vector(const std::vector<T>& V)
{
std::copy(V.begin(), V.end(), std::ostream_iterator<T>(std::cout, " ")); // you don't even need this function right?
//for(int i=0; i < V.size(); i++)
// std::cout << V[i] << " ";
}
You can do similar things for the cin.

Invalid use of template-name ‘Matrix’ without an argument list

Here is my Matrix.cpp file. (there's a separate Matrix.h file)
#include <iostream>
#include <stdexcept>
#include "Matrix.h"
using namespace std;
Matrix::Matrix<T>(int r, int c, T fill = 1)
{
if (r > maxLength || c > maxLength) {
cerr << "Number of rows and columns should not exceed " << maxLen << endl;
throw 1;
}
if (r < 0 || c < 0) {
cerr << "The values for the number of rows and columns should be positive" << endl;
throw 2;
}
rows = r;
cols = c;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
mat[i][j] = fill;
}
This gives the following
error: invalid use of template-name ‘Matrix’ without an argument list
What's the problem in my code?
EDIT: The class Matrix is defined with a template<class T>
EDIT:
Here's my Matrix.h file:
#include <iostream>
#include <math.h>
#define maxLength 10;
using namespace std;
template <class T>
class Matrix
{
public:
Matrix(int r, int c, T fill = 1);
private:
int rows, cols;
T mat[10][10];
};
And here's the Matrix.cpp file:
#include <iostream>
#include <stdexcept>
#include "Matrix.h"
using namespace std;
template<class T>
Matrix<T>::Matrix(int r, int c, T fill = 1)
{
}
This gives the following error:
Matrix.cpp:12:43: error: default argument given for parameter 3 of
‘Matrix::Matrix(int, int, T)’ Matrix.h:16:3: error: after previous
specification in ‘Matrix::Matrix(int, int, T)’
What is wrong in my code?
If your class is template then correct definition should be,
template<class T>
Matrix<T>::Matrix(int r, int c, T fill) // don't give default argument
...
Also, don't forget to include this Cpp file where you use this class. Because in the case of templates, full body should be visible to all translation units.
Edit: After your edited question, I noticed that the error says it all.
You are not suppose to give the default argument inside the definition of the method. It's adequate to give in the declaration(which you already gave). Make your template definition as shown above and the error shall disappear.
You should write as:
template<class T>
Matrix<T>::Matrix(int r, int c, T fill = 1)
{
..
}
Yes, it's tedious. And it might not be a good idea to put
the template definitions in the source file, refer to
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
So the easiest way is to put the definitions of the template members
inside the class template definition in header file.