Help with Templates

Started by
6 comments, last by godecho 15 years, 10 months ago
Hello All I have used templates all within a header file for a while now, but when I try and separate the code into .h and .cpp files it breaks :( It all worked fine when all the hash class functions were all in the header file within the class itself. I really need to have this in separate header and source files, due to I plan to put this in a library with other classes, and if it all has to be in the header file then it’s not worth having the library. Anyone know how to resolve this, I have looked for the last few hours, looking at example code and trying how they did it, but it still fails to compile :( What am I doing wrong ? Oh btw I am using Visual Studio 2003 if that helps.

// Error:
storage.obj : error LNK2019: unresolved external symbol "public: void __thiscall HashTable<int,class Player>::Initialize(int)" 
(?Initialize@?$HashTable@HVPlayer@@@@QAEXH@Z) referenced in function "public: __thiscall Storage::Storage(void)" (??0Storage@@QAE@XZ)


I have removed the bulk of the code or the post would of been very long. Hash Header File

// hash.h
template<typename KeyType, typename DataType> class HashTable
{
public:
    ...
    void Initialize(int p_size);
    ...
};


Hash Source File

// hash.cpp

#include "hash.h"

template<typename KeyType, typename DataType>
void HashTable<KeyType, DataType>::Initialize(int p_size)
{
    ...
}


Storage Header File

// storage.h
class Storage
{
public:
    HashTable<int, class Player> playerlist;
    HashEntry<int, class Player>* player;

    Storage();
    ...
};


Storage Source File

// storage.cpp

#include "hash.h"
#include "storage.h"

Storage::Storage()
{
	playerlist.Initialize(MAX_PLAYER_CELL);

}


Thanks in advance Paul Kirby
Advertisement
Unless your compiler supports the 'export' keyword (which most don't) you need to put templates in the header file itself, or somehow include the template 'source' file into the header, or explicitly instantiate the templates.

Some people will make a file to put the template implementation into and #include it into the template header towards the file. These files usually get a different extension, for example '.tcc'.

I just put the template implementation code into the header file.
Quote:Original post by rip-off
Unless your compiler supports the 'export' keyword (which most don't) you need to put templates in the header file itself, or somehow include the template 'source' file into the header, or explicitly instantiate the templates.

Some people will make a file to put the template implementation into and #include it into the template header towards the file. These files usually get a different extension, for example '.tcc'.

I just put the template implementation code into the header file.


Thanks for the very fast reply :)

Well I have created a file called "templateinstantiations.cpp" with the following in it.

// templateinstantiations.cpp#include "hash.cpp"#include "item.h"#include "player.h"#include "ship.h"template class HashTable<int, class Player>;    // explicit instantiation  template class HashTable<int, class Item>;      // explicit instantiation  template class HashTable<int, class Ship>;      // explicit instantiation


This fixed the errors that I was getting, however how would I put this in a library?

This file includes "hash.cpp" and when using a library file I wouldn't have access to "hash.cpp" only the header files.

And I can't put the 3 template class lines in hash.h or hash.cpp due to it doesn't know about the Player, Item or Ship Classes, which it shouldn't need to know about.

Thanks in advance
Paul Kirby
Quote:Original post by TheMightyDude
This fixed the errors that I was getting, however how would I put this in a library?

Basically, you wouldn't.

That's why the STL (or if anyone are pedantic enough to make a fuss about it, the STL-derived parts of the C++ Standard Library) is basically a bunch of header files.
There's no library for std::vector or std::for_each. They reside in header files because they're templates.

There's no good way around it.
If you expose a template, the entire template definition has to be visible in the same compilation unit. So you can't hide it away in a .cpp file, and supply it as a library.
Move the template function definitions back into the header file, and get rid of your explicit instantiations. And never #include a .cpp file.

Have a read:
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
Thanks for all the replies...

I had a bad feeling that it would be better off all in the header file :(

I guess the next best thing is to put these header files in their own folder and include it when needed.

Thanks
Paul Kirby
Quote:Original post by TheMightyDude
how would I put this in a library?

Templates are only compiled once they're instantiated and used elsewhere, this is because the compiler needs to first know what the template parameters are going to be - so it wouldn't make sense to be able to compile a templated class/function into a library.
It's possible to separate the class definition and the implementations, but they still have to be in the same file. This can be handy for readability:

template <class Foo>class Bar{    public:        Bar();        void Qux();        // other stuff};template <class Foo>Bar<Foo>::Bar(){}template <class Foo>void Bar<Foo>::Qux(){}

This topic is closed to new replies.

Advertisement