[c++] "Undefined reference to" template class constructor

I have no idea why this is happenning, since I think I have everything properly declared and defined.

I have the following program, designed with templates. It's a simple implementation of a queue, with the member functions "add", "substract" and "print".

I have defined the node for the queue in the fine "nodo_colaypila.h":

#ifndef NODO_COLAYPILA_H
#define NODO_COLAYPILA_H

#include <iostream>

template <class T> class cola;

template <class T> class nodo_colaypila
{
        T elem;
        nodo_colaypila<T>* sig;
        friend class cola<T>;
    public:
        nodo_colaypila(T, nodo_colaypila<T>*);

};

Then the implementation in "nodo_colaypila.cpp"

#include "nodo_colaypila.h"
#include <iostream>

template <class T> nodo_colaypila<T>::nodo_colaypila(T a, nodo_colaypila<T>* siguiente = NULL)
{
    elem = a;
    sig = siguiente;//ctor
}

Afterwards, the definition and declaration of the queue template class and its functions:

"cola.h":

#ifndef COLA_H
#define COLA_H

#include "nodo_colaypila.h"

template <class T> class cola
{
        nodo_colaypila<T>* ult, pri;
    public:
        cola<T>();
        void anade(T&);
        T saca();
        void print() const;
        virtual ~cola();

};


#endif // COLA_H

"cola.cpp":

#include "cola.h"
#include "nodo_colaypila.h"

#include <iostream>

using namespace std;

template <class T> cola<T>::cola()
{
    pri = NULL;
    ult = NULL;//ctor
}

template <class T> void cola<T>::anade(T& valor)
{
    nodo_colaypila <T> * nuevo;

    if (ult)
    {
        nuevo = new nodo_colaypila<T> (valor);
        ult->sig = nuevo;
        ult = nuevo;
    }
    if (!pri)
    {
        pri = nuevo;
    }
}

template <class T> T cola<T>::saca()
{
    nodo_colaypila <T> * aux;
    T valor;

    aux = pri;
    if (!aux)
    {
        return 0;
    }
    pri = aux->sig;
    valor = aux->elem;
    delete aux;
    if(!pri)
    {
        ult = NULL;
    }
    return valor;
}

template <class T> cola<T>::~cola()
{
    while(pri)
    {
        saca();
    }//dtor
}

template <class T> void cola<T>::print() const
{
    nodo_colaypila <T> * aux;
    aux = pri;
    while(aux)
    {
        cout << aux->elem << endl;
        aux = aux->sig;
    }
}

Then, I have a program to test these functions as follows:

"main.cpp"

#include <iostream>
#include "cola.h"
#include "nodo_colaypila.h"

using namespace std;

int main()
{
    float a, b, c;
    string d, e, f;
    cola<float> flo;
    cola<string> str;

    a = 3.14;
    b = 2.71;
    c = 6.02;
    flo.anade(a);
    flo.anade(b);
    flo.anade(c);
    flo.print();
    cout << endl;

    d = "John";
    e = "Mark";
    f = "Matthew";
    str.anade(d);
    str.anade(e);
    str.anade(f);
    cout << endl;

    c = flo.saca();
    cout << "First In First Out Float: " << c << endl;
    cout << endl;

    f = str.saca();
    cout << "First In First Out String: " << f << endl;
    cout << endl;

    flo.print();
    cout << endl;
    str.print();

    cout << "Hello world!" << endl;
    return 0;
}

But when I build, the compiler throws errors in every instance of the template class:

undefined reference to `cola(float)::cola()'... (it's actually cola'<'float'>'::cola(), but this doesn't let me use it like that.)

And so on. Altogether, 17 warnings, counting the ones for the member functions being called in the program.

Why is this? Those functions and constructors WERE defined. I thought that the compiler could replace the "T" in the template with "float", "string" or whatever; that was the advantage of using templates.

I read somewhere here that I should put the declaration of each function in the header file for some reason. Is that right? And if so, why?

Thanks in advance.

This question is related to c++ templates compiler-errors codeblocks

The answer is


You will have to define the functions inside your header file.
You cannot separate definition of template functions in to the source file and declarations in to header file.

When a template is used in a way that triggers its intstantation, a compiler needs to see that particular templates definition. This is the reason templates are often defined in the header file in which they are declared.

Reference:
C++03 standard, ยง 14.7.2.4:

The definition of a non-exported function template, a non-exported member function template, or a non-exported member function or static data member of a class template shall be present in every translation unit in which it is explicitly instantiated.

EDIT:
To clarify the discussion on the comments:
Technically, there are three ways to get around this linking problem:

  • To move the definition to the .h file
  • Add explicit instantiations in the .cpp file.
  • #include the .cpp file defining the template at the .cpp file using the template.

Each of them have their pros and cons,

Moving the defintions to header files may increase the code size(modern day compilers can avoid this) but will increase the compilation time for sure.

Using the explicit instantiation approach is moving back on to traditional macro like approach.Another disadvantage is that it is necessary to know which template types are needed by the program. For a simple program this is easy but for complicated program this becomes difficult to determine in advance.

While including cpp files is confusing at the same time shares the problems of both above approaches.

I find first method the easiest to follow and implement and hence advocte using it.


This link explains where you're going wrong:

[35.12] Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?

Place the definition of your constructors, destructors methods and whatnot in your header file, and that will correct the problem.

This offers another solution:

How can I avoid linker errors with my template functions?

However this requires you to anticipate how your template will be used and, as a general solution, is counter-intuitive. It does solve the corner case though where you develop a template to be used by some internal mechanism, and you want to police the manner in which it is used.


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to templates

*ngIf else if in template 'if' statement in jinja2 template How to create a link to another PHP page Flask raises TemplateNotFound error even though template file exists Application not picking up .css file (flask/python) Django: How can I call a view function from template? Angularjs Template Default Value if Binding Null / Undefined (With Filter) HTML email in outlook table width issue - content is wider than the specified table width How to redirect on another page and pass parameter in url from table? How to check for the type of a template parameter?

Examples related to compiler-errors

intellij idea - Error: java: invalid source release 1.9 Error:Execution failed for task ':app:transformClassesWithJarMergingForDebug' Deserialize JSON with Jackson into Polymorphic Types - A Complete Example is giving me a compile error Android java.exe finished with non-zero exit value 1 error: expected primary-expression before ')' token (C) What does "collect2: error: ld returned 1 exit status" mean? Python3: ImportError: No module named '_ctypes' when using Value from module multiprocessing Maven error :Perhaps you are running on a JRE rather than a JDK? What does a "Cannot find symbol" or "Cannot resolve symbol" error mean? Operator overloading ==, !=, Equals

Examples related to codeblocks

How to change text color and console color in code::blocks? error CS0103: The name ' ' does not exist in the current context Can't find file executable in your configured search path for gnc gcc compiler How do you specify a debugger program in Code::Blocks 12.11? How to use graphics.h in codeblocks? undefined reference to WinMain@16 (codeblocks) Cannot open include file with Visual Studio How can I add C++11 support to Code::Blocks compiler? C++ Boost: undefined reference to boost::system::generic_category() fatal error: iostream.h no such file or directory