Building C++ Applications with Template Classes in Visual Studio

Background

When working with "normal" C++ classes the recommended procedure is to put a class definition in a C++ header file, e.g. myClass.h, and the implementation in a C++ source file, e.g., myClass.cpp. The source file is then made part of the project, meaning it is compiled separately. The client program, e.g., driver.cpp, then has an #include "myClass.h" so when it is compiled the compiler will know about myClass.

However, a problem arises when this recommendation is applied to template classes. In a nutshell, it just wonít work. The reason for the problem and possible solutions are discussed below.

Why there is a Problem

The fundamental problem is that a template per se cannot be compiled. Or, perhaps it is more accurate to say there is nothing to be compiled in the template itself. For example, consider the template class definition:

template(class ObjectType)
class myClass{

private:

ObjectType x;

Etc.
};

If the compiler sees only this, it canít compile anything because it doesnít know what ObjectType is going to be! Nothing can be compiled until you actually instantiate an object from the template. At that time you specify the typename:

MyClass<int> anObject;

Once the compiler sees this, it can substitute int wherever ObjectType appears in the template. Then the class can be compiled and the object can be compiled to object code. Thus if you put your template in a separate myClass.cpp file and compile it, the compiler has nothing to do! However, no error or warning will be given. It is quite happy with the easy task you have given it!

The second problem is that when the compiler does encounter a declaration of a myClass object of some specific type, e.g., int, it must have access to the template implementation source. Otherwise, it will have no idea how to construct the myClass member functions. And if you have put the implementation in a source (myClass.cpp) file and made it a separate part of the project, the compiler will not be able to find it when it is trying to compile the client source file. Merely #including the header file (myClass.h) will not suffice. That only tells the compiler how to allocate for the object data, and how to build the calls to the member functions, not how to build the member functions. And again, the compiler wonít complain. It will assume that these functions are provided elsewhere, and leaves it to the linker to find them. So, when itís time to link you will get "unresolved references" to any of the myClass member functions that ate not defined "inline" in the class definition.

What to Do about It

Here are three commonly used approaches.

  1. Probably the most widely used approach is to simply abandon the recommendation for non-template classes and put the entire template class implementation in the header file. Some may find this appalling, but this is what appears to be done in the Standard Template Library. With this approach there is no myClass.cpp file at all; hence, it canít be made part of the project.
  2. If for any reason you do not want to put you implementation in the header file, put it in myClass.cpp. Then, at the end of you myClass.h, put

  3. #include "myClass.cpp"
    This has exactly the same effect as method 1. This is probably the best approach for CPSC 331 students since Weiss has all his implementations in separate .cpp files. Itís a lot easier than cutting and pasting! Note that with this approach you must enclose your myClass.h file in an #ifndef/endif, e.g.,

    #ifndef MYCLASS_H

    #define MYCLASS_H

    // the class definition

    #endif
    Otherwise, you will wind up including the class definition endlessly, since the #include "myClass.h" often occurs myClass.cpp (although it neednít be there). Also note that if you take this approach you do not have to make myClass.cpp part of the project. They get compiled along with the client.

  4. Another approach used by some programmers is to simply instantiate a few of myClass objects in a separate myClass.cpp file. For example,

  5. myClass<int> myClassIntNeverUsed;
    myClass<float> myClassFloatNeverused;
    myClass<double> myClassDoubleNeverUsed;
    This will cause the compiler to compile these particular types, so the associated class member functions will be available at link time. Strange, but it works. Indeed, some IDEs (Symantec) allow you to say you want these objects to be instantiated, so you donít have to actually put them your source files.