tags:

views:

1268

answers:

6

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?

+9  A: 

As a general rule, you must put all template members inside of the header file. Templates are compiled an an as used basis and hence the entire definition needs to be available wherever they are used. Putting the code in the header file solves 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.

JaredPar
You can also put templatized member functions of a non-templatized class into the cpp file if you're never going to call them elsewhere (so enforce this, they should be private, but they don't have to be).
rmeador
+1  A: 

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.

antti.huima
A: 

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.

Jimmy J
I still don't get it. Why can't template be a class, with separate header and the source code?Let's say I want to write my own List<T> .. do I have to include every List<T> method into header file?
Yes, that's the most common way. You can also #include "List.cpp" at the bottom of List.h.
Kristo
ok then. I found it strange to include everything into header file - the actual code is a bit longer than the few lines in the question (it's a binary search tree).
The compiler has to generate different machine code for each possible data type but it can't do that unless it knows which types are needed. You wouldn't want it to make code for every possible data type...(!)
Jimmy J
+5  A: 

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.

Kristo
A: 

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.

If you think this is a bad answer, you can delete it before you get downvoted.
Max Lybbert
+1  A: 

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