views:

178

answers:

2

I'm not an experienced C++ programmer and I'm having problems compiling. I've got a Heap class that uses a template:

template <class T>
class Heap
{
  public:
    Heap(const vector<T>& values);

  private:
    vector<T> d;

  // etc.
};

And then in a separate implementation file:

template <class T>
Heap<T>::Heap(const vector<T>& values)
{
d = values;

for (unsigned int i = d.size()-1; i > 0; i--) Heapify(ParentIndex(i));
}

// ... more implementation code ...

And finally a main.cc file:

int main (int argc, char *argv[])
{
  vector<int> in;
  unsigned int i;

  while (cin >> i) in.push_back(i);
  Heap<int> h = Heap<int>(in);

  return 0;
}

I get these compile errors:

g++ -Wall -I/opt/local/include -c -o main.o main.cc
g++ -Wall -I/opt/local/include -c -o heap.o heap.cc
g++ -Wall -o heap main.o heap.o
Undefined symbols:
  "Heap<int>::Heap(std::vector<int, std::allocator<int> > const&)", referenced from:
      _main in main.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [heap] Error 1

Why does this not compile? I think the linker is saying it can't find the constructor, but I know it made the object file.

+7  A: 

Templates need to be defined 100% within the header file. If you have your Heap<T> implementation in a .cc / .cpp file that is the problem. Move all of the code to the header file and it should fix your issue.

JaredPar
You can also keep them physically separate by #including the implementations into the header
Cogwheel - Matthew Orlando
@Cogwheel, true but including a .cpp file is usually a bad sign in code. I prefer either 1) everything in a .h or 2) putting code in a .inl file. The different file extension makes it much clearer what the intent is
JaredPar
@JaredPar, yep. I usually use .inl.
Cogwheel - Matthew Orlando
Well, this is a good rule of thumb, but I do define some templates in .cpp file in particular cases (when they are only used in those files). I would need someone with better worlds like litb to offer a full explanation though :)
Matthieu M.
+3  A: 

According to the C++ standard, you can use the export keyword thus:

export template<typename foo>...

However, most compilers don't support this. The C++ FAQ has some more info: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.14

See JaredPar's answer for something that's actually reliable.

Cogwheel - Matthew Orlando
"export" was one of those things the Standards Committee stuck in without prior experience, and it shows. It's hard to implement, and doesn't seem to do what anybody really wants anyway.
David Thornley