This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 8 years ago.
I'm trying to make a simple bounds checked array in C++. I have declared a class in a header file, and defined the class in a separate source file. The compile step runs fine, but when I try to link the objects, I get the following error:
$ g++.exe -o a.exe src\main.o src\array.o
src\main.o: In function `main':
../src/main.cpp:7: undefined reference to `Array<int>::Array(int)'
../src/main.cpp:9: undefined reference to `Array<int>::operator[](int)'
../src/main.cpp:10: undefined reference t o `Array<int>::operator[](int)'
../src/main.cpp:11: undefined reference t o `Array<int>::operator[](int)'
../src/main.cpp:13: undefined reference t o `Array<int>::operator[](int)'
../src/main.cpp:7: undefined reference to `Array<int>::~Array()'
../src/main.cpp:7: undefined reference to `Array<int>::~Array()'
collect2.exe: error: ld returned 1 exit status
main.cpp
#include <iostream>
#include "array.hpp"
using namespace std;
int main() {
Array<int> x(10); // compiler error
x[0] = 1; // compiler error
x[1] = 2; // compiler error
x[2] = 3; // compiler error
cout << x[1] << endl; // compiler error
return 0;
}
array.hpp
#ifndef ARRAY_HPP_
#define ARRAY_HPP_
template <class T>
class Array{
private:
T* array;
int length_;
public:
Array(int);
~Array();
int Length();
int& operator[](int);
};
#endif /* ARRAY_HPP_ */
array.cpp
#include "array.hpp"
template <class T>
Array<T>::Array(int size) {
length_ = size;
array = new T[size];
}
template <class T>
Array<T>::~Array() {
delete[] array;
}
template <class T>
int Array<T>::Length() {
return length_;
}
template <class T>
int& Array<T>::operator[](const int index) {
if (index < 0 || index >= length_) {
throw 100;
}
return array[index];
}
Definitions of members of a template class shall be in the same header where the template class is defined itself.
Template classes must have all their code in the header file or they can only be used for types you explicitly instantiated in the cpp file.
Related
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 3 years ago.
I tried to make an Array template class but when I try to build the compiler fails to link the constructor and the method and I get :
undefined reference to `Array::Array()
undefined reference to `Array::getSize()
Here is the header file:
#pragma once
template<typename type, int length>
struct Array{
public:
Array();
int getSize();
private:
type data[length];
int m_length;
};
The Array.cpp file:
#include "Array.h"
template<typename t, int l>
Array<t, l>::Array()
{
m_length = l;
}
template<typename type, int length>
Array<type, length>::getSize()
{
return m_length;
}
And the main function:
#define LOG(x) cout<<x<<endl
int main()
{
Array<int, 10> array;
LOG(array.getSize());
}
If someone has any idea about why I am getting this, I would really appreciate.
You need to either put your implementation into the header files, or define the usage (instantiation of the template arguments) in the source file
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I have this class in my .hpp file
template<class T = int>
class Matrix
{
public:
Matrix();
}
and I have this Matrix.cpp file
#include "Matrix.hpp"
template<class T>
Matrix<T>::Matrix()
{
vector<T> vecN(1, 0);
_matrix.resize(1, vecN);
_rows = 1;
_cols = 1;
}
but it won't work, when adding a main
#include "Matrix.hpp"
int main(int argc, char** argv)
{
Matrix<int> test();
return 0;
}
i get a very weird error saying
main.cpp:19: undefined reference to Matrix<int>::Matrix(unsigned int, unsigned int)'
main.cpp:19:(.text+0x2d): relocation truncated to fit: R_X86_64_PC32 against undefined symbol Matrix<int>::Matrix(unsigned int, unsigned int)
Template code must be in the header, unless it is for specialisations.
This is because the template is used to generate the actual class when you use it.
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Why do I get "unresolved external symbol" errors when using templates? [duplicate]
(3 answers)
Closed 9 years ago.
I have 3 files - main, Array.hh, and Array.cc. When I do "g++ main.cc Array.cc", I get all kinds of linker errors, e.g.: "undefined reference to Array<<\double>>::Array(int)"
I read the other stackoverflow entries for linker errors with templates, but they are recommending to split the HH and CC files, which I have already done. So what can be the problem here?
Edit: Thanks for the replies. I had not understood the posts I had read previously. Merging the Array.cc into the Array.hh solves the problem. Closed.
main.cc:
#include "Array.hh"
#include <iostream>
int main() {
Array<int> anArray(12);
Array<double> adArray(12);
for (int nCount = 0; nCount < 12; nCount++) {
anArray[nCount] = nCount;
adArray[nCount] = nCount + 0.5;
}
for (int nCount = 11; nCount >= 0; nCount--)
std::cout << anArray[nCount] << "\t" << adArray[nCount]
<< std::endl;
return 0;
}
Array.hh:
template <typename T>
class Array {
private:
int m_nLength;
T *m_ptData;
public:
Array();
Array(int nLength);
~Array();
void Erase();
T& operator[](int nIndex);
int GetLength();
};
Array.cc
#include "Array.hh"
template <typename T>
Array<T>::Array() {
m_nLength = 0;
m_ptData = 0;
}
template <typename T>
Array<T>::Array(int nLength) {
m_ptData= new T[nLength];
m_nLength = nLength;
}
template <typename T>
Array<T>::~Array() { delete[] m_ptData; }
template <typename T>
void Array<T>::Erase() {
delete[] m_ptData;
m_ptData= 0;
m_nLength = 0;
}
template <typename T>
int Array<T>::GetLength() { return m_nLength; }
Put the definitions from Array.cc into Array.hh
When a template class is used, a class is created. Array.cc does not know which classes should be created from the template, only main.cc knows that. main.cc does not know how to create the classes, because it does not know the definition of the member functions of Array, only Array.cc knows that.
You need to #include "Array.cc"
A template can't be instantiated if its definition is not available.
This separation of definition and declaration is fine, but you must include the cc file whereever you are instatiating that template with a new type
Recommendations you took are not very accurate. You should not separate your templates into .h and .cpp files.
If you insist on putting them separate, "export" is the keyword you are looking for.
For more information about "export" check here: http://www.parashift.com/c++-faq/separate-template-fn-defn-from-decl-export-keyword.html.
This question already has answers here:
"Undefined reference to" template class constructor [duplicate]
(3 answers)
Closed 6 years ago.
I have three files . The contents of main.cpp are
#include<iostream>
#include<QString>
#include "util.h"
int main()
{
using Util::convert2QString;
using namespace std;
int n =22;
QString tmp = convert2QString<int>(n);
return 0;
}
util.h
namespace Util
{
template<class T>
QString convert2QString(T type , int digits=0);
}
util.cpp
namespace Util
{
template<class T>
QString convert2QString(T type, int digits=0)
{
using std::string;
string temp = (boost::format("%1%") % type).str();
return QString::fromStdString(temp);
}
}
When I try to compile these files with following command I get undefined reference error
vickey#tb:~/work/trash/template$ g++ main.cpp util.cpp -lQtGui -lQtCore -I. -I/usr/local/Trolltech/Qt-4.8.0/include/QtCore -I/usr/local/Trolltech/Qt-4.8.0/include/QtGui -I/usr/local/Trolltech/Qt-4.8.0/include
/tmp/cca9oU6Q.o: In function `main':
main.cpp:(.text+0x22): undefined reference to `QString Util::convert2QString<int>(int, int)'
collect2: ld returned 1 exit status
Is there something wrong with the template declaration or implementation ? why M I getting these linking errors :?
The implementation of a non-specialized template must be visible to a translation unit that uses it.
The compiler must be able to see the implementation in order to generate code for all specializations in your code.
This can be achieved in two ways:
1) Move the implementation inside the header.
2) If you want to keep it separate, move it into a different header which you include in your original header:
util.h
namespace Util
{
template<class T>
QString convert2QString(T type , int digits=0);
}
#include "util_impl.h"
util_impl.h
namespace Util
{
template<class T>
QString convert2QString(T type, int digits=0)
{
using std::string;
string temp = (boost::format("%1") % type).str();
return QString::fromStdString(temp);
}
}
You have 2 ways:
Implement convert2QString in util.h.
Manually instantiate convert2QString with int in util.cpp and define this specialization as extern function in util.h
util.h
namespace Util
{
template<class T>
QString convert2QString(T type , int digits=0);
extern template <> QString convert2QString<int>(int type , int digits);
}
util.cpp
namespace Util {
template<class T>
QString convert2QString(T type, int digits)
{
using std::string;
string temp = (boost::format("%1") % type).str();
return QString::fromStdString(temp);
}
template <> QString convert2QString<int>(int type , int digits);
}
I found this vector template class implementation, but it doesn't compile on XCode.
Header file:
// File: myvector.h
#ifndef _myvector_h
#define _myvector_h
template <typename ElemType>
class MyVector
{
public:
MyVector();
~MyVector();
int size();
void add(ElemType s);
ElemType getAt(int index);
private:
ElemType *arr;
int numUsed, numAllocated;
void doubleCapacity();
};
#include "myvector.cpp"
#endif
Implementation file:
// File: myvector.cpp
#include <iostream>
#include "myvector.h"
template <typename ElemType>
MyVector<ElemType>::MyVector()
{
arr = new ElemType[2];
numAllocated = 2;
numUsed = 0;
}
template <typename ElemType>
MyVector<ElemType>::~MyVector()
{
delete[] arr;
}
template <typename ElemType>
int MyVector<ElemType>::size()
{
return numUsed;
}
template <typename ElemType>
ElemType MyVector<ElemType>::getAt(int index)
{
if (index < 0 || index >= size()) {
std::cerr << "Out of Bounds";
abort();
}
return arr[index];
}
template <typename ElemType>
void MyVector<ElemType>::add(ElemType s)
{
if (numUsed == numAllocated)
doubleCapacity();
arr[numUsed++] = s;
}
template <typename ElemType>
void MyVector<ElemType>::doubleCapacity()
{
ElemType *bigger = new ElemType[numAllocated*2];
for (int i = 0; i < numUsed; i++)
bigger[i] = arr[i];
delete[] arr;
arr = bigger;
numAllocated*= 2;
}
If I try to compile as is, I get the following error:
"Redefinition of 'MyVector::MyVector()'"
The same error is displayed for every member function (.cpp file).
In order to fix this, I removed the '#include "myvector.h"' on the .cpp file, but now I get a new error:
"Expected constructor, destructor, or type conversion before '<' token".
A similar error is displayed for every member as well.
Interestingly enough, if I move all the .cpp code to the header file, it compiles fine. Does that mean I can't implement template classes in separate files?
It's always a good idea to place your templates in a header file. That way you don't mess up the linker with multiple definitions of the same instantiations and such.
And of course there's the circular inclusion :).
First, you have
#include "myvector.cpp"
which creates a circular reference between the files. Just get rid of it.
The other problem is that you are defining a template class inside a .cpp file. Template definitions are only allowed inside header files. There may be ways around that, but for g++ (which XCode uses) that's how the cookie crumbles.