undefined reference to template function [duplicate] - c++

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

Related

Undefined reference to struct method [duplicate]

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

Undefined reference error in C++ Link step [duplicate]

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.

C++ class template undefined reference to function [duplicate]

This question already has answers here:
undefined reference to template function [duplicate]
(2 answers)
Closed 6 years ago.
I keep getting undefined reference when i call the two functions from my template class "add" and "greater" in my main function.
So, i have:
number.h
#ifndef NUMBER_H
#define NUMBER_H
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
#endif
number.cpp
#include "number.h"
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
And my main file is: resolver.cpp
#include <stdio.h>
#include <stdlib.h>
#include "number.h"
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
The errors that i keep getting are:
g++ -Wall -o tema1 resolver.cpp number.cpp
/tmp/ccX483J4.o: In function `main':
resolver.cpp:(.text+0x34): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x47): undefined reference to `number<int>::add(int&)'
resolver.cpp:(.text+0x64): undefined reference to `number<int>::greater()'
collect2: ld returned 1 exit status
make: *** [all] Error 1
Thanks for the help in advance!
I prefer to have all of my functions in the .cpp file, regardless of whether they are template functions or regular functions. And there is a way to do that with some basic #ifndef magic. Here's what you can do:
main.cpp
#include "myclass.hpp"
int main()
{
// ...
}
myclass.hpp
#ifndef MYCLASS
#define MYCLASS
template<class T>
class MyClass
{
T val;
public:
MyClass(T val_);
}
#define MYCLASS_FUNCTIONS
#include "myclass.cpp"
#endif
myclass.cpp
#ifndef MYCLASS_FUNCTIONS
#include "myclass.hpp"
// regular functions:
// ...
#else
// template functions:
template<class T>
MyClass<T>::MyClass(T val_)
:val(val_)
{}
// ...
#endif
Here's how the precompiler sees it. We have two .cpp files.
When we compile main.cpp we:
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the generated class (from template class)
include myclass.cpp
define MYCLASS_FUNCTIONS
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definitions of the generated functions (from template functions)
When we compile myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it isn't
include myclass.hpp
check that MYCLASS is undefined, and it is
define it
give compiler the definitions of the class
include myclass.cpp
include myclass.hpp again
this time MYCLASS is defined so do nothing inside, return to myclass.cpp
check if MYCLASS_FUNCTIONS is defined, it is
give compiler the definition of the generated functions (from template functions)
exit include twice
pass to the compiler all the regular functions
Your class is named wrong. Your class is named cai where all your functions belong to a class named number: http://ideone.com/ZayX0c
One more thing.. you cannot have templates in the .cpp file. Template functions/defintions go in the header along with the class declaration. This is the reason for your undefined function error. Non-template functions go in the .cpp.
#include <cstdio>
#include <cstdlib>
template <class T>
class number {
public:
T x;
T y;
number (int a, int b){
x=a; y=b;}
int add (T&);
T greater ();
};
template <class T>
int number<T>::add (T& rezAdd){
rezAdd = x+y;
return 1;
}
template <class T>
T number<T>::greater (){
return x>y? x : y;
}
int main (int argc, char **argv) {
int aux;
number<int> c(3,5);
c.add(aux);
printf ("number added [%d]\n", c.add(aux));
printf ("greater number: [%d]\n", c.greater());
return 0;
}
Move the definitions of the add and greater function templates into your number.h.
Remember that add and greater aren't functions, they're function templates. To create actual functions, the compiler has to instantiate the template for specific types, such as int, and it can only do that if it has access to the template's definition at the point where it discovers that an instance is needed.
When you compile number.cpp, the compiler has access to the templates' definitions, but it doesn't see any code that requires a specific instance (such as number<int>), so it doesn't generate instances.
When you compile resolver.cpp, the compiler sees that it needs to instantiate those templates for the int type, but it can't since it doesn't have their definitions. So it generates "external references", basically notes telling the linker to look for those functions in some other object file.
The result is that the function templates don't get instantiated in either object file — in one because the compiler didn't know that it should, and in the other because it couldn't — so when the linker goes looking for them (to resolve those external references), it can't find them. That's why you get the error.
Moving the template function definitions into the header makes them visible to the compiler while it's compiling main.cpp, so it's able to instantiate those functions for the int type. Function templates typically need to be defined in header files, rather than .cpp files, for exactly this reason.

A strange 'undefined reference to' error with g++ [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
"undefined reference" to a template class function
(4 answers)
Closed 9 years ago.
See my demo code below:
b.hpp:
#ifndef B_HPP
#define B_HPP
namespace debug {
class test {
public:
template <class T> void foo(T a);
private:
int a;
};
}
#endif
b.cpp:
#include <iostream>
#include "b.hpp"
namespace debug {
template <class T>
void test::foo(T a) {
std::cout << "debug" << std::endl;
}
}
testb.cpp:
include "b.hpp"
int main(int agrc, char *argv[])
{
debug::test a;
int c = 5;
a.foo(c);
return 0;
}
I compile it with
g++ -std=c++11 testb.cpp b.cpp'
and get a error:
/tmp/ccnjR5S4.o: In function `main':
testb.cpp:(.text+0x1c): undefined reference to `void debug::test::foo<int>(int)'
collect2: error: ld returned 1 exit status
What's the problem?
If I put main function in b.cpp and compile b.cpp, it 's ok. Why?
Thanks!
This is one of the cases where you need explicit instantiation, or to move code back into b.hpp. This arises because the implementation of debug::test::foo isn't visible when you compile testb.cpp, and the compiler has no way of knowing what might be needed when it compiles b.cpp.
To explicitly instantiate debug::test::foo<int>, add the following line to b.cpp:
#include <iostream>
#include "b.hpp"
namespace debug {
template <class T>
void test::foo(T a) {
std::cout << "debug" << std::endl;
}
// Explicitly instantiate test::foo<int>
template void test::foo<int>(int); // <-- add this line
}
Alternately, if you do not know all the ways this template might get instantiated, move its definition back into the class definition in the header. Ugly, but it'll work.
Some compilers do cross-compilation unit template instantiation, but as you've discovered, g++ isn't one of them. (At least, not as it's configured on my system.)
Edit: As #juanchopanza pointed out above, this thread gives a good explanation of what's going on: Why can templates only be implemented in the header file?

Understanding template classes in c++ - problem with new-operator

Dear all, I've been stuck with this problem now for a few days and my searches were not successful.
What I am trying to do:
I want a template reader class (VariableReader) to handle different types of variables (usually unsigned int and pointers to vector).
I started with
#ifndef READER_H_
#define READER_H_
#include <string>
namespace BAT {
template <typename variableType = unsigned int>
class VariableReader {
public:
VariableReader<variableType>();
VariableReader<variableType>(std::string varName);
virtual ~VariableReader<variableType>();
std::string getVariableName();
void setVariableName(std::string varName);
bool isValidVariableName(std::string varName);
variableType getVariable();
private:
std::string variableName;
variableType variable;
};
}
#endif
and
#include "../../interface/Readers/VariableReader.h"
namespace BAT {
template<typename variableType>
VariableReader<variableType>::VariableReader() :
variableName("") {
// TODO Auto-generated constructor stub
}
template <typename variableType>
VariableReader<variableType>::VariableReader(std::string varName) :
variableName(varName) {
}
template <typename variableType>
std::string VariableReader<variableType>::getVariableName() {
return variableName;
}
template <typename variableType>
void VariableReader<variableType>::setVariableName(std::string varName) {
if (VariableReader::isValidVariableName(varName)) {
variableName = varName;
}
}
template <typename variableType>
bool VariableReader<variableType>::isValidVariableName(std::string varName) {
return varName != "";
}
template <typename variableType>
VariableReader<variableType>::~VariableReader() {
// TODO Auto-generated destructor stub
}
}
However, although it seems to compile I can't use it within other projects.
EDIT: forgot to post test-code:
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
#include "Readers/VariableReader.h"
using namespace BAT;
static VariableReader<int> *reader;
void setUp(){
reader = new VariableReader<int>::VariableReader();//this is problem-line
}
void thisIsATest() {
ASSERTM("start writing tests", false);
}
void runSuite(){
cute::suite s;
//TODO add your test here
s.push_back(CUTE(thisIsATest));
cute::ide_listener lis;
cute::makeRunner(lis)(s, "The Suite");
}
int main(){
runSuite();
}
I get following error message:
Building target: BAT_Tests
Invoking: GCC C++ Linker
g++ -L"/workspace/BAT/Debug Gcov" -fprofile-arcs -ftest-coverage -std=c99 -o"BAT_Tests" ./src/Test.o -lBAT
./src/Test.o: In function `setUp()':
/workspace/BAT_Tests/Debug Gcov/../src/Test.cpp:13: undefined reference to `BAT::VariableReader<int>::VariableReader()'
collect2: ld returned 1 exit status
make: *** [BAT_Tests] Error 1
As I understand it the linker tries to find the constructor for VariableReader, which is not explicitly defined since I want to have a general constructor only.
Please help me to understand what I am missing.
The C++ FAQ Lite section on How can I avoid linker errors with my template functions? shows two solutions:
Move the template class's methods into the .h file (or a file included by the .h file).
Instantiate the template in the .cpp file using template VariableReader<unsigned int>;.
The constructor(s) and destructor doesn't need the template arguments in it. In addition, template classes must have the full source available to compile- you can't declare the members and define them in another translation unit like you can with normal classes.