Karel Bílek
Karel Bílek

Reputation:

c++ class with template cannot find its constructor

I have a problem I don't really understand. I have a class Node.

template<class T>
class node {
protected:
    T _data;
public:
    node(T data);   
};

This is in "node.h" file. In "node.cpp" file, there is this constructor:

#include "node.h"

template<class T>
node<T>::node (T data) {
    _data = data;
}

While the compiler finds no error, the linker (ld) tells me:

/usr/bin/ld: Undefined symbols:

node<int>::node(int)

the weird part... if I move the constructor from .cpp to .h file, everything works fine. Where is the problem?

Upvotes: 15

Views: 18326

Answers (7)

Syed Mamun Raihan
Syed Mamun Raihan

Reputation: 11

// You can put templates declaration in header and definition in source  
// node.h or wherever you include file gets included
extern template class node<int>;

// node.cpp or where ever source file you want to use it
// But use it only once for each type of generated class
template class node<int>;

Upvotes: 1

JaredPar
JaredPar

Reputation: 755567

As a general rule, you must put all template members inside of the header file. Templates are compiled in an as-used basis, and hence the entire definition needs to be available wherever they are used. Putting the code in the header file will solve that problem.

The only time you can put a template definition in a CPP file is when the template will only be used within that CPP file. The reason being is that it meets the standard that the entire definition is available for compilation.

Moving the contents of node.cpp to node.h will fix the problem.

Strange Scenarios

Then again, you can also put everything in a CPP file and include the CPP file. C++ is flexible in this way. I only mention this because I've seen in done before. I actually bruised my jaw when it hit the top of my desk.

Upvotes: 13

Mark Ransom
Mark Ransom

Reputation: 308530

The commonly accepted practice is to put all of the implementation in the .h file, so that the classes can be generated from the template as needed.

If you know ahead of time which types your template will be instantiated with, you might be able to cheat a little. Just make sure your .cpp includes a use case for each type and method you will need. It is important that the use case come after the template code. E.g. for "node.cpp", use

#include "node.h"

template<class T>
node<T>::node (T data) {
    _data = data;
}

void dummy(void)
{
    node<int> intnode(0);
    node<double> doublenode(0.0);
}

Upvotes: 1

Michael Kristofik
Michael Kristofik

Reputation: 35218

The problem is that templates aren't classes - you don't normally write them in two separate files. Template classes are code that the compiler uses to generate classes. As such, your implementation code needs to effectively be inline, i.e., in the header as you discovered.

For a fuller explanation of why it has to be this way, see the C++ FAQ Lite.

Upvotes: 24

ka3ak
ka3ak

Reputation:

implicit instantiation is turned off, you need

template class node<int>;

somewhere in your code (node.cpp maybe)

EDIT: bad answer, it's probably not the case.

Upvotes: 1

Jimmy J
Jimmy J

Reputation: 1985

Unless there's a call to the function, the compiler won't output any code and the linker won't find it.

You should put the function in the header where it belongs.

Upvotes: 0

Antti Huima
Antti Huima

Reputation: 25542

When you use node<int>, you have not most likely included node.cpp. Therefore the compiler cannot instantiate the node<int>::node<int> constructor. Usually you put all the template code, including all the implementations of the methods, in the header file, or something included from it.

Upvotes: 1

Related Questions