Link error using templates - c++

I converted a function to a template, and started getting this error. I must not be understanding a limitation of templates. Can someone tell me why this is broken?
I am receiving this error:
Undefined symbols:
"bool foo<int>(int const&, int const&)", referenced from:
_main in file1.o
ld: symbol(s) not found
When I link the following code. The code is simplified, but still fails. The first file contains:
#include <iostream>
template <class T> bool foo (const T&, const T&);
int main ()
{
int left = 1;
int right = 2;
if (foo <int> (left, right))
std::cout << "foo!" << std::endl;
return 0;
}
And the second file contains:
template <class T> bool foo (const T& left, const T& right)
{
return true;
}

For the reason Uri gave, template methods are usually defined in the header file. Because yours is a function and not a method of a class, explicitly define it (in the header file which may be included by more than one CPP file) as static or inline.
Put this in your foo.h
template<class T> inline bool foo (const T& left, const T& right)
{
return true;
}
Put this in your main.cpp
#include <iostream>
#include "foo.h"
int main ()
{
int left = 1;
int right = 2;
if (foo <int> (left, right))
std::cout << "foo!" << std::endl;
return 0;
}
The cpp code now sees the whole declaration of the template function.
Other solutions are listed here: How can I avoid linker errors with my template functions?

It's been years since I did much C++, but I think you are encountering a problem of separate compilation. Templates are instantiated at compilation, not linking.
Therefore, when you are making the call to foo(), you are not really instantiating the template in the sense that no new function code is generated, you're just creating a symbol that the linker has to resolve.
However, when the second file is compiled, it has just the template and it is never instantiated, so no version of foo() that actually deals with ints is generated. As a result, when you link everything together, you get the error.
I'm not 100% sure what to do about this, but I suspect that you would need to force an instantiation of foo() with ints in that second file (assuming it's a C++).
I only worked with class templates, not function templates, I'm sure someone here will give you the exact code in a few...

Related

extern declared template specialized function not found

i'm trying to implement a clone of the json serialization library nlohmann::json as a learning experience, and i'm having trouble with the interface for user defined (json<->User type) conversion.
Basically i want the user to be able to overload two function: to_json(json&, const Type&) and from_json(const json&, Type&). Then the library will use overload resolution to call theses function in the templated operator= and one argument constructor.
It works fine when i'm just defining theses function directly but when i try to make a template definition for multiple types (in this example the class S) the linker can't find the definition.
I've tried to explicitly instantiate the function for individual instances of the templated class although i would prefer avoiding having to do that in the final product.
I'm guessing it has to do with the fact that templated function don't have the same signature than free function, but i don't see what i can do to make it work. What am i missing ? I also couldn't find result on google so is it a documented pattern or an anti pattern ?
Thanks you. Below i tried to minimize my problem in one short example.
Class.hpp
#pragma once
#include <cstdio>
template<size_t i>
class S {
size_t n = i;
};
template<size_t i>
void g(const S<i>& s) {
printf("S<%u>\n", i);
}
Class.cpp
#include "Class.hpp"
template void g<10>(const S<10>&); // <-- Even with explicitly instanciation
void g(const bool& b) {
printf("%s\n", b ? "true" : "false");
}
main.cpp
#include "Class.hpp"
template<typename T>
void f(T t) {
extern void g(const T&);
g(t);
}
int main(int, char**) {
S<10> s;
//f(s); <-- linker error: void g(class S<10> const &) not found.
f(false);
}
The name lookup for g in g(t) call stops as soon as it finds extern void g(const T&); declaration; it never sees the declaration of the function template. So the compiler generates a call to a regular non-template function named g taking const S<10>&. But no such function is defined in your program - hence linker error.

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.

Use arbitrary functions as template parameter arguments

I have an Apache module (.so) that contains a class I'm trying to completely decouple from Apache itself. The biggest source of frustration is the debug logging. I want to be able to pass the logging function to the class through the template parameters. I can get the proof of concept to work fine when everything is in the same translation unit, but it falls over once they're not because the logging function is an 'undefined reference':
/tmp/ccPdPX2A.o: In function `main':
test.cpp:(.text+0x81): undefined reference to `void C::DoThis<&(LogIt(char const*, ...))>()'
collect2: ld returned 1 exit status
This also happens when Apache tries to load the module containing the class.
The code below reproduces the problem:
// main.cpp
#include <iostream>
#include "C.h"
void LogIt(const char*, ...)
{
std::cout << "GADZOOKS!\n";
}
int main(int argc, char* argv[])
{
C c;
c.DoThis<LogIt>();
}
// C.h
typedef void (*LogFunction)(const char*, ...);
class C
{
public:
template <LogFunction L>
void DoThis();
template <LogFunction L>
void DoThat();
};
// C.cpp
#include "C.h"
template <LogFunction L>
void C::DoThis()
{
L("DoThis!");
DoThat<L>();
}
template <LogFunction L>
void C::DoThat()
{
L("DoThat!");
}
I'd prefer not to have to resort to having the function passed as a function parameter, i.e.
template <typename F>
void C::DoThis(F f)
{
f("DoThis!");
}
because I'd like to structure the code in such a way that the compiler is able to figure out if the body of LogIt is empty (which it will be for Release builds) and not generate any code for the call, and I'd have to pass it as an argument everywhere in the class.
Can it be done?
Okay I recreated everything,
This error undefined reference to void C::DoThis<&(LogIt(char const*, ...))>() is explained here
Now if you do #include "C.cpp" referring above, this will lead to
undefined reference to void C::DoThat<&(LogIt(char const*, ...))>()
So fix:
template <LogFunction L>
void C::DoThat() //Notice :: used here
{
L("DoThat!");
}
and everything complies and execute !
This is because you have your templates invisible at the point where compiler is supposed to instantiate them as you only have a declaration in C.h and a definition in C.c.
Either move template definitions to header or force instantiation in C.c. You will have to provide LogIt declaration in C.c for that.
You need to put template definition in the same as the place where its declared. So that means you need to put your LogIt function where it was declared in the header file. As of right now, we are not able to explicitly separate template declaration and its definition like that.

Templates and separate compilation

I want to write a program in C++ with separate compilation and I wrote this:
main.cpp
#include <iostream>
#include "Stack.h"
using namespace std;
int main(int argc,char* argv[])
{
Stack<int> st;
st.push(1);
return 0;
}
Stack.h
#ifndef _STACK_H
#define _STACK_H
template<typename T>
class Stack
{
private:
struct Node
{
Node* _prev;
T _data;
Node* _next;
};
int _size;
Node* _pos;
public:
Stack();
T pop();
void push(T const &el);
int getSize() const;
};
#endif
Stack.hpp
#include "Stack.h"
#include <malloc.h>
template <typename T>
Stack<T>::Stack()
{
_size = 0;
_pos = (Node*)malloc(sizeof(Node));
_pos->_prev = NULL;
_pos->_next = NULL;
}
template <typename T>
T Stack<T>::pop()
{
if (_size == 0)
return NULL;
T tmp = _pos->_data;
if (_pos->_prev == NULL)
free(_pos);
else
{
_pos->_prev->_next = _pos->_next;
if (_pos->_next != NULL)
{
_pos->_next->_prev = _pos->_prev;
}
free(_pos);
}
_size--;
return tmp;
}
template <typename T>
void Stack<T>::push(T const &el)
{
Node* n = (Node*)malloc(sizeof(Node));
_pos->_next = n;
n->_prev = _pos;
n->_data = *el;
_pos = n;
_size ++;
}
template<typename T>
int Stack<T>::getSize() const {return _size;};
I compiled the program with g++ and I get this error:
ccyDhLTv.o:main.cpp:(.text+0x16): undefin
ed reference to `Stack<int>::Stack()'
ccyDhLTv.o:main.cpp:(.text+0x32): undefin
ed reference to `Stack<int>::push(int const&)'
collect2: ld returned 1 exit status
I know that the problem is because I'm using templates but I do not know how to fix it.
OS - Windows
compilation line - g++ main.cpp Stack.h Stack.hpp -o main.exe
Template classes need to have the method definitions inside the header file.
Move the code you have in the .cpp file inside the header, or create a file called .impl or .imp, move the code there, and include it in the header.
The compiler needs to know the method definitions to generate code for all specializations.
Before you ask, no, there is no way to keep the implementation outside the header.
I would say it will be more pragmatic to first understand how separate compilation works for normal (untempelated) files and then understand how g++ compiler does it for template.
First in normal files, when the header file containing only the declarations are #included in main file, the preprocessor replaces the declarations from the header and puts it to the main file. Then after the preprocessing phase is over, the compiler does one by one compilation of the pure C++ source code contained in .cpp files and translates it into object file. At this point the compiler doesn't mind the missing definitions (of functions/classes) and the object files can refer to symbols that are not defined. The compiler, hence can compile the source code as long as it is well formed.
Then during the linking stage the compiler links several files together and it is during this stage the linker will produce error on missing/duplicate definitions. If the function definition is correctly present in the other file then the linker proceeds and the function called from the main file is successfully linked to the definition and can be used.
For templates, things work differently. It will be illustrative to consider an example, so I pick a simple one:
consider the header file for template array class:
array.h
#ifndef _TEMPLATE_ARRAY_H_
#define _TEMPLATE_ARRAY_H_
template <class T>
class Array
{
private:
T *m_list;
int m_length;
public:
Array() //default constructor
{
m_list = nullptr;
m_length = 0;
}
Array(int length)
{
m_list = new T[length];
m_length = length;
}
~Arrary()
{
delete[] m_list;
m_list = nullptr;
}
//undefined functions
int getLength();
T getElement(const int pos);
};
and the corresponding array.cpp file :
include "array.h"
template <class T>
array<T>::getLength()
{ return m_length; }
template <class T>
T Array<T>::getElement(const int pos)
{ return m_list[pos]; }
Now consider the main file where two instances of the templated object array, one for int and another for double is created.
main.cpp
#include "array.h"
#include <iostream>
int main()
{
Array<int> int_array;
Array<double> double_array;
std::cout << int_array.getLength() <<"\n";
std::cout << double_array.getLength() << "\n";
}
When this piece of code is compiled, the preprocessor first copies the template declarations from the header file to the main file as usual. Because in the main file Array< int > and Array< double > objects are instantiated, compiler instantiates two different definitions of Array class, one each for double and int and then instantiate the Array objects in the main.cpp file.
Note till this point the function definitions for Array< int >::getLength() and Array< double >::getLength() is still missing in the main.cpp file but since the source code is well formed the compiler compiles the main.cpp file without any hassle. In short there's no difference b/w templated object/function compilation and non-templated function compilation till now.
In the meanwhile the code file for array.cpp containing the template function definitions for Array< T >::getLength() and Array< T >::getElement() is compiled, but by this time the compiler would have forgotten that main.cpp needs Array< int >::getLength() and Array< double >::getLength() and would happily compile the code array.cpp without generating any instances for int and double version of the function definition needed by the main.cpp file. (Remember that compiler compiles each file separately!)
It is during the linking phase horrible template errors start popping because of the missing function definitions for int and double version of template function definition that are required by the main file. In the case of non-template declarations and definitions, the programmer makes sure to define the sought function in a file which can be linked together with the file calling the function. But in the case of templates, the linker which executes after the compilation phase, cannot do a task that a compiler is suppose to do, i.e generate a code, in this case for int and double type of the template function
There are ways to get around this
Having gone through the entire story, one can easily conclude that the entire fuss up around template separate compilation is due to linkage (i.e) if all codes are written correctly, class and functions declared in header and defined in another separate file). Ways of getting around this are :
Define the class and functions in the header files themselves rather than in separate file so that the contents of header file when included in the main file, includes the templated definitions which cause appropriate instances of necessary functions to be defined by the compiler.
Instantiate the type definitions you know you will need in the separate file where the template definitions are written. This will then directly be linked to the function calls in the main file.
Another way to get around this is to name the .cpp file where definitions are written to .inl* file (from the e.g drawn above, chagne array.cpp to array.inl); inl means inline and include the .inl file from the bottom of the header file. This yields the same result as defining all functions within the header file but helps keeping the code a little cleaner.
There's another way, i.e #include .cpp file with templated definitions in the main file which I personally don't prefer because of non-standard usage of #include.
It is absolutely possible to have templates and separate compilation, but only if you know in advance for which types the template will be instantiated.
Header file sep_head.h:
template< typename T >
class sep{
public:
sep() {};
void f();
};
Main:
#include "sep_head.h"
int main() {
sep<int> s; s.f();
sep<double> sd; sd.f();
sep<char> sc; sc.f();
return 0;
}
Implementation:
#include "sep_head.h"
template< typename T >
void sep<T>::f() {}
template class sep<int>;
template class sep<double>;
template class sep<char>;

Undefined symbols for typedef and template? [duplicate]

This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 6 years ago.
This seems so simple, but I cannot figure out what's wrong. I'm implementing the C++ vector class (only for int, not a template), and functions with iterator templates or typedefs are giving me these errors on compile:
Undefined symbols:
"void vectorInt::assign<int>(int, int)", referenced from:
_main in ccNVdR23.o
"void vectorInt::assign<int*>(int*, int*)", referenced from:
_main in ccNVdR23.o
_main in ccNVdR23.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Important parts for the source files are:
vectorInt.h
#include <cstdlib>
#include <stdexcept>
typedef unsigned int size_type;
class vectorInt {
private:
int* array;
size_type current_size;
size_type current_capacity;
public:
.
.
.
template <class InputIterator>
void assign(InputIterator first, InputIterator last);
void assign(size_type n, const int u);
};
#endif // VECTORINT_H
vectorInt.cpp
#include vectorInt.h
.
.
.
template <class InputIterator>
void vectorInt::assign(InputIterator first, InputIterator last) {
clear();
InputIterator it = first;
int count = 0;
while(it++ != last) {
count++;
}
reserve(count);
while(first != last) {
this->push_back(*first++);
}
}
void vectorInt::assign(size_type n, const int u) {
clear();
reserve(n);
for(int i=0; i<(int)n; i++)
push_back(u);
}
main.cpp
#include <cstdlib>
#include <stdexcept>
#include <iostream>
#include "vectorInt.h"
using namespace std;
int main(int argc, char** argv) {
vectorInt first;
vectorInt second;
vectorInt third;
first.assign(7, 100);
vectorInt::iterator it;
it = first.begin()+1;
second.assign(it, first.end()-1); // the 5 central values of first
int myints[] = {1776,7,4};
third.assign(myints, myints+3); // assigning from array.
return 0;
}
FYI: I know the main method uses the vectorInt::iterator, but that is not the problem and hence I didn't include it in the source code.
Template code gets two phase compilation. Phase one includes only basic syntax check. The second phase, which is dependent on type T, gets full compilation from the compiler. The class/function will get instantiated based on type T, and the second phase compilation will run against that type.
Since your code (implementation) is in .cpp file, it would get only first phase compilation, and thus it will not be included in the translation unit - No object file would be generated.
For templates, you must allow the compiler to compile the entire code. And for the same you need to put entire implementation in header file only. You may also #include respective .cpp file just after the class declaration.
Place the code for the assign functions in the header file (vectorint.h) and you should be fine. Code for templates needs to be visible when they are instanciated, in you case where you call the assign function.