Recommended Posts

blueshogun96    2264

I recently converted my linked list code from C to C++ using templates.  Afaik, my functions are clearly defined, but my compiler (XCode) still doesn't like it.  Here's an example function definition:

template <class T>
class node_t
{
node_t();
virtual ~node_t();

public:
T data;
node_t<T>* next;
};

template <class T>
void list_add_end( node_t<T>** list, T data );

And this is a usage example:

class base_process_t
{
base_process_t();
virtual ~base_process_t();

public:
virtual void foo1() PURE;
virtual void foo2() PURE;
};

list_add_end<base_process_t*>( &process_list, new base_process_t() );

This all compiles fine, but doesn't link.  The typical error I get is:

Undefined symbols

"list_add_end<base_process_t*>( node_t<base_process_t*>**, base_process_t* )" referenced from (blah blah blah)

This isn't really making any sense to me.  Is it because of my classes using virtual functions by chance?  This is my first time attempting to do this, and after all the years I've been using C++, I can't believe I'm stumped on a seemingly minuscule problem, and I have the feeling I'm going to feel really stupid once I figure this out.  This sucks.  Any ideas?  Thanks.

Shogun

Share on other sites
Juliean    7068
template <class T>
void list_add_end( node_t<T>** list, T data );


Where is the definition of that function? The reason for this error could be that it is simply missing.

Share on other sites
blueshogun96    2264

It's not missing, but I solved the problem though.

The template functions needed to be moved from a .cpp to a .inl and the functions needed to be inlined.  Then include the .inl instead of .hpp, and that solved everything.

Shogun.

Share on other sites
Rattrap    3385

The template functions needed to be moved from a .cpp to a .inl and the functions needed to be inlined.  Then include the .inl instead of .hpp, and that solved everything.

Yup. Templates need to be contained in a header file, not a cpp, as you discovered. This can cause some headache if you end up with circular dependences that would normally just be solved by separating the definitions from the declarations in a h/CPP pairing.

Share on other sites
SeanMiddleditch    17565

The template functions needed to be moved from a .cpp to a .inl and the functions needed to be inlined.  Then include the .inl instead of .hpp, and that solved everything.

You don't _strictly_ need this. The only rule is that the linker can find a definition of your template. You could keep your template in a .cpp file so long as the .cpp knows exactly what to instantiate explicitly (e.g. if you only use <int> and <float> with your template, declare those as 'extern' and then explicitly instantiate them in your .cpp file with the template code). This is less flexible but makes things compile faster if used well and appropriately in larger projects, which may be of interest.

Share on other sites
NightCreature83    5002
template <class T>
void list_add_end( node_t<T>** list, T data );


If all you do is modify what the list pointer needs to point at please write this in the C++ way, which looks like this:

template <class T>
void list_add_end( node_t<T>*& list, T data );


Also means you don't have to write your pointer modification code like this anymore:

node_t<t>* newNode = new node_t<T>();
*list = &newNode;

//instead you can just write this
node_t<t>* newNode = new node_t<T>();
list = newNode;

Edited by NightCreature83