Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
109 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Template Gotchas

You can't separate your class definitions into source and header files like you normally would

The problem is that most compilers do not remember the details between different source (.cpp, .cxx etc) files. As stated above, classes and functions that you define with templates aren't really classes and functions. They are considered template patterns and these patterns are used to generate the actual classes. This causes issues with the compiler, since templates aren't really classes, and only become classes when you actually declare them. The compiler can't actually allow you to have your implementation in your source file and header (h/.hpp etc) without a bit of tinkering around.

A lot of people like to put their actual implementation in the source file while keeping the class declaration in header files. This allows them to glance through the header file to see the functionality the class provides. However, this is not easy to achieve with templates.

One solution is to have all your code inlined within the header file. The main disadvantage to this technique is that you loose the benefit of separating the implementation from the declaration and the ability to see the functionality of a class at a glance.

What many people do is place both their implementation and declaration in the header file. They do not inline the actual implementation but rather keep it separate from the declaration.

For example:

template <typename T>
class MyClass
{
private:
  T x;
public:
  
  T GetX();
};

template <typename T>
T MyClass<T>::GetX()
{
  return x;
}

One common mistake many people make when separating the code from the implementation, is that they forget that every bit of code outside the class declaration has to be within its own template declaration. Another common mistake is to declare the implementation just as you would inside the class like MyClass::GetX(). This is not correct. As pointed out before, once you use templates it's no longer MyClass, it's MyClass<T>.

Another approach is to separate the implementation into another file. You include this file at the bottom of the header using the #include directive.

Some people keep the extension ".cpp". However this file must not be included in the compilation process and therefore a extension like ".tpl" is better. In Visual C++, for example, you have to make sure you do not include it in the project manager. Other compiler implementations make sure it's not within the makefile.

Another solution is to use the 'export' keyword to achieve this functionality; however, at this time only the Comeau compiler actually supports this keyword. Although there is a lot of talk in the standards community about removing the export keyword, it will remain in the next revision of the C++ Standard because it provides at least a conceptual benefit.

Templates with Smart Pointers

Smart pointers are objects that manage the destruction and aspects of a pointer's lifetime, and take care of a lot of the safety issues for you. Through the use of operator overloading they are designed to give you the "feel" of an ordinary pointer.

One smart pointer that the C++ standard provides is std::auto_ptr. The standard auto_ptr provides a lot of great functionality, however, one of its big problems is that you can't really use it with C++ containers or anything using a template. The C++ standard has defined using auto_ptr with templates and containers as undesirable due to the ownership transfer semantics.

STL Containers and smart pointers have become quite popular now-a-days. Containers like std::vector allow you the flexibility of allowing quick and easy storage for your objects and values without having to roll out your own solutions like linked lists. Smart pointers allow you to have your memory cleaned up efficiently without having to worry about the details yourself.

Containers like std::vector don't provide any sort of memory cleanup. If you use a std::vector with a pointer it's your responsibility to go through and cleanup the pointers it contains.

Consider using boost::shared_ptr from the boost suite of libraries. Not only will it work with templates and STL containers but it also has a lot of advanced features like reference counting etc. I have been using it myself for all my smart pointer needs. You can find information about it here: http://www.boost.org. Another popular Smart Pointer is part of the Loki library by Andrei Alexandrescu and you can find information about it here: http://sourceforge.net/projects/loki-lib/.

Some people get tripped up when defining a smart pointer and container combo. For example a lot of people might initially define it as this:

std::vector<boost::smart_ptr<CGameObject>> ObjectContainer;

The difficulty is the >> after CGameObject. This gets interpreted as the bit shift operator. The way around this is to simply place a space between the first and second like so:

std::vector<boost::smart_ptr<CGameObject> > ObjectContainer;

I'm using Visual C++ 6, and I'm getting compile errors/warnings. Am I doing something wrong?

Not necessarily. Visual C++ 6 was released just before the standardisation committee finished finalising the C++ standard. Therefore some of the features introduced in the standard are incomplete or incorrect. One of the areas that suffer quite a bit is templates. The implementation of STL provided by Microsoft is actually licensed from Dinkumware. Some advanced features may be missing in Visual C++ 6 like partial template specialisation.

My top recommendation to remedy this problem is to upgrade to Visual C++ 7.1 (2003 edition) or above. This version of Visual C++ is over 98% standards compliant and the majority of issues in early versions have been fixed. If you are a student you can get a cheap copy of Visual Studio Academic version. It provides similar level of functionality as the Pro version of Visual Studio with a few extra student tools. It does however have licensing issues. Also the standard version of Visual C++ 7.1 is quite cheap and is enough for the hobbyist game programmer with optimisation features missing.

If you end up keeping Visual C++ 6, for whatever reasons, you might want to consider the following options.

  1. You can actually replace your STL implementation in Visual C++ with one provided by http://www.stlport.com. The library is free and is well worth the download. To install, download the software off the site, read the readme files on how to install for Visual C++.
  2. Dinkumware - the guys who actually make the STL implementation for Visual C++ - have released updates to the libraries which can be downloaded here: http://www.dinkumware.com/vc_fixes.html
  3. Make sure you have installed the latest service pack provided by Microsoft. Service packs update functionality and fix problems with releases. You can find the latest service pack for Visual Studio here: http://msdn.microsoft.com/vstudio/downloads/updates/sp/vs6/sp5/default.aspx
  4. There is a way of disabling warnings inside of Visual C++. When the compiler brings up warnings it generally has a number associated with it, e.g. C4786. You can actually plug in those numbers into a pragma statement. A pragma statement is a way of giving the compiler a command; in this case we want to disable a warning message. Some people might be tempted to use this for all warnings, however, this isn't recommended because it might hide the bugs in your code. You should only use this technique for warnings associated with the inadequacies in Visual C++ 6. Most people place their pragma statement inside their stdafx.h file.

    For example you could put the following:
    // identifier was truncated to 'number' characters in
    #pragma warning( disable : 4786 )
    // 'function' : function not inlined
    #pragma warning( disable : 4710 )
    

Unfortunately, some of the template problems with Visual C++ 6 are inherent to the compiler and changing the library may not help resolve all of them.

Resources/References

http://msdn.microsoft.com/ - The definitive source of MSVC information.

http://www.sgi.com/tech/stl/ - More details on STL than MSDN.

http://www.gotw.ca/ - Herb Sutter - Guru of the Week

http://www.cuj.com - C++ Users Journal

Effective STL, Scott Meyers

Effective C++, Scott Meyers

More Effective C++, Scott Meyers




Contents
  What are templates?
  Template Gotchas

  Printable version
  Discuss this article