tags:

views:

51

answers:

2

I have created an example below to illustrate the problem I'm having. Basically, when I separate a template class into separate .h/.cpp file, I get unresolved symbols for the constructor. Using a single file, it compiles fine. What is causing this?

fruits.cpp:

#include "apple.h"

class FruitsDB {
    public:
        void addApple();
};

void FruitsDB::addApple() {
    Apple<int> m;
}

int main() {
    FruitsDB fruits;
    return 0;
}

apple.h:

template <typename T>
class Apple {
    public:
        Apple();
        ~Apple();
};

apple.cpp

template <typename T>
Apple<T>::Apple() {
}

template <typename T>
Apple<T>::~Apple() {
}

This produces the compiler error:

g++    -c -o fruits.o fruits.cpp
g++    -c -o apple.o apple.cpp
g++ -Wall -ggdb fruits.o apple.o -o fruits
Undefined symbols:
  "Apple<int>::Apple()", referenced from:
      FruitsDB::addApple()     in fruits.o
  "Apple<int>::~Apple()", referenced from:
      FruitsDB::addApple()     in fruits.o
ld: symbol(s) not found

I thought it was my code causing the problem, but consolidating files doesn't produce the problem. I'm assuming I need to include a file somewhere where I'm not. I'm totally lost.

Note: Adding template <> Apple<int>::Apple() {} in apple.cpp will resolve this, but I'm using templates to avoid having to write all those constructors, etc.

+3  A: 

Just put your template function definitions in your header files. The thing about template functions is, they aren't actually functions. They are templates of functions. So they can't be compiled out of context like normal functions. They can only be compiled if the template parameters are known. So the compiling is done when the file that uses them calls the function. In order for that to happen, the template needs to be visible to the file from which it is called, which is why you put it in the header.

PigBen
I always get confused whether they are "template functions" or "function templates" :-)
ArunSaha
+1  A: 

In theory, under the current C++ standard, you can fix your code by adding the export keyword to the templates.

In reality, only one compiler (Comeau C++) has ever really supported export, and it's one with quite a small market share. There are a couple of other compilers based on the EDG front end that also accept code that contains the export keyword, and might handle your code correctly, but don't officially support it, so if it doesn't work, you're on your own (e.g., Intel C++). Since it's almost completely un-implemented (largely because it's close to un-implementable and seems to provide little real benefit in any case) the C++ standard committee has voted to remove export from the next standard.

That leaves putting the complete definition of each template (directly or indirectly) into a header file as essentially the only way to make your code work.

Jerry Coffin
+1: Like the balance between the Standard and the Reality.
Chubsdad