3

I'm implementing a hash table and linked list in C++ (no STL - don't ask) using templates, and I'm running into problems linking them with g++. If I #include all my .cpp files together, everything works, so my code definitely works, it's just the linking that's tripping me up.

I read the bit in the GCC manual about template instantiation, but wasn't sure how to apply it.

My problem: I have a HashMap<T> and HashEntry<T> for my hash table (<T> is the value - my keys are std::strings). My linked list has LinkedList<T> and Node<T> (where <T> is the value).

In my hash map, I have:

template <class T> class HashMap {
    ...
    private:
        LinkedList< HashEntry<T> >** buckets;
 }

Which gives me a linked list of HashEntry<T>s.

In a separate file, I have my Linked List class declaration:

template <class T>
    class Node {
        ...
        private:
             T data;
}

template <class T> class LinkedList {
     ...
     private:
     Node<T> * first;
}

Then, when I try to link everything (after compiling with g++ -c -frepo *.cpp), I get:

g++ -frepo -o app LinkedList.o HashMap.o
[...unrelated errors about not having a main method - they go away when I link that in]
HashMap.o: In function `HashMap<int>::~HashMap()':
HashMap.cpp:(.text._ZN7HashMapIiED1Ev[HashMap<int>::~HashMap()]+0x65): undefined reference to `LinkedList<HashEntry<int> >::~LinkedList()'
HashMap.o: In function `HashMap<int>::insert(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int)':
HashMap.cpp:(.text._ZN7HashMapIiE6insertESsi[HashMap<int>::insert(std::basic_string<char,     std::char_traits<char>, std::allocator<char> >, int)]+0xff): undefined reference to     `Node<HashEntry<int> >::setData(HashEntry<int>)'

Googling around, I've seen suggestions for declaring the explicit template types that my program uses. This works for the HashMap and HashEntry (I added (template class HashMap< int > and template class HashEntry< int >.

However, I can't figure out how to make this work for LinkedList and Node classes, since the template instances are of HashEntries<int>. BUT, I can't put that into the LinkedList.h file, since it's #included by my Hash tables. I also couldn't get an advanced/extern declaration working for it.

I'm sure there's something fairly simple that I'm missing to make all this work. Any tips?

Tomas Aschan
  • 58,548
  • 56
  • 243
  • 402
Taj Morton
  • 33
  • 1
  • 3
  • Is there a definition of your `LinkedList` destructor anywhere? Or `Node<...>::setData()`? – robert Dec 22 '10 at 00:04
  • Probably unrelated, but is there any reason you're not using something like make, waf, SCons, etc.? – robert Dec 22 '10 at 00:05
  • @kotlinski: Correct, my HashMap uses the LinkedList (for chaining), and I've got a `#include "LinkedList.h"` at the top of my file. – Taj Morton Dec 22 '10 at 00:05
  • @robert: I've got my ~LinkedList() and setData in the .cpp file (`template LinkedList::~LinkedList()`). Again, it compiles if I #include all my .cpp files together. No build system - just trying to get it working from scratch for now. – Taj Morton Dec 22 '10 at 00:07

2 Answers2

4

If you are making template classes, it is not a good idea to put them in .cpp files and compile separately. The right way is to put them in .h files (both declaration and definition) and include them where you need them.

The reason is that templates won't actually be compiled unless their template arguments are defined.

(Intentionally avoiding mentioning the export keyword.)

Johan Kotlinski
  • 25,185
  • 9
  • 78
  • 101
  • 1
    You know, there's that `export` thingy getting removed in C++0x... oh right :P +1 – Billy ONeal Dec 22 '10 at 00:16
  • Thanks - I guess I'll make that work. For now I'm just #including my .cpp file into the .h file. Is that an alright thing to do, or should I really move the code inside my class declaration? – Taj Morton Dec 22 '10 at 00:25
  • @Taj Morton move it inside the class declaration. Including a cpp file is generally considered bad form. – robert Dec 22 '10 at 00:35
2

It looks like you're defining template class members in LinkedList.cpp. Templates generally need to be completely defined (not just declared) in the .h file. For ways around this, see storing C++ template functions in a .cpp file. But I would avoid it--it causes more problems than it's worth.

Community
  • 1
  • 1
robert
  • 33,242
  • 8
  • 53
  • 74