Search

14.3 — Template classes

In the previous two lessons, you learn how function templates and function template instances could be used to generalize functions to work with many different data types. While this is a great start down the road to generalized programming, it doesn’t solve all of our problems. Let’s take a look at an example of one such problem, and see what templates can do for us further.

Templates and container classes

In the lesson on container classes, you learned how to use composition to implement classes that contained multiple instances of other classes. As one example of such a container, we took a look at the IntArray class. Here is a simplified example of that class:

While this class provides an easy way to create arrays of integers, what if we want to create an array of doubles? Using traditional programming methods, we’d have to create an entirely new class! Here’s an example of DoubleArray, an array class used to hold doubles.

Although the code listings are lengthy, you’ll note the two classes are almost identical! In fact, the only substantive difference is the contained data type. As you likely have guessed, this is another area where templates can be put to good use to free us from having to create classes that are bound to one specific data type.

Creating template classes works pretty much identically to creating template functions, so we’ll proceed by example. Here’s the IntArray classes, templatated version:

Array.h:

As you can see, this version is almost identical to the IntArray version, except we’ve added the template declaration, and changed the contained data type from int to T.

Note that we’ve also defined the GetLength() function outside of the class declaration. This isn’t necessary, but new programmers typically stumble when trying to do this for the first time due to the syntax, so an example is instructive. Each templated member function declared outside the class declaration needs its own template declaration. Also, note that the name of the templated array class is Array<T>, not Array -- Array would refer to a non-templated version of a class named Array.

Here’s a short example using the above templated array class:

This example prints the following:

11     11.5
10     10.5
9       9.5
8       8.5
7       7.5
6       6.5
5       5.5
4       4.5
3       3.5
2       2.5
1       1.5
0       0.5

Templated classes are instanced in the same way templated functions are -- the compiler stencils a copy upon demand with the template parameter replaced by the actual data type the user needs and then compiles the copy. If you don’t ever use a template class, the compiler won’t even compile it.

Template classes are ideal for implementing container classes, because it is highly desirable to have containers work across a wide variety of data types, and templates allow you to do so without duplicating code. Although the syntax is ugly, and the error messages can be cryptic, template classes are truly one of C++’s best and most useful features.

Splitting up template classes

A template is not a class or a function -- it is a stencil used to create classes or functions. As such, it does not work in quite the same way as normal functions or classes. In most cases, this isn’t much of a problem. However, there is one area that commonly causes problems.

With non-template classes, the common procedure is to put the class definition in a header file, and the member function definitions in a similarly named code file. In this way, the source for the class is compiled as a separate project file. However, with templates, this does not work. Consider the following:

Array.h:

Array.cpp:

main.cpp:

The above program will compile, but cause a linker error:

unresolved external symbol "public: int __thiscall Array::GetLength(void)" (?GetLength@?$Array@H@@QAEHXZ)

This happens because main.cpp can’t see the template definition of Array::GetLength().

There are quite a few ways to work around this.

The easiest way is to simply put all of your template class code in the header file (in this case, put the contents of Array.cpp into Array.h). In this way, when you #include the header, all of the template code will be in one place. The upside of this solution is that it is simple. The downside here is that if the template class is used in many places, you will end up with many local copies of the template class, which can bloat your code. This is our preferred solution unless code bloat becomes a problem.

Other solutions involve #including .cpp files, but we don’t recommend these because of the non-standard usage of #include.

An alternative way is to use a three-file approach. The template class definition goes in the header. The template class member functions goes in the code file. Then you add a third file, which contains all of the instantiated classes you need:

templates.cpp:

The “template class” command causes the compiler to explicitly instantiate the templated class. In the above case, the compiler will stencil out both Array and Array inside of templates.cpp. Because templates.cpp is inside our project, this will then be compiled. These functions can then be linked to from elsewhere.

This method is more efficient, but requires maintaining the templates.cpp file.

14.4 -- Expression parameters and template specialization
Index
14.2 -- Function template instances

29 comments to 14.3 — Template classes

  • Vinitha Krishnamurthy

    Alex,

    I think, IntArray class uses composition and not aggregation. It is a value container class and not a reference container class.

    Vinitha

    [ I am constantly amazed by the attention to detail that my readers possess. Very nice catch, and I appreciate you bringing it to my attention. -Alex ]

  • Gilles

    T Array::GetLength() shall return an int instead of a T

    [ Fixed! Thanks. -Alex ]

  • Tobi

    should be

    ?

  • Pradeep

    Hi Alex,

    The template version you provied if instatiated by a ‘char’ it may cause problems becaue incounstructor you gave “new T[length] but for char it needs ‘new T[length+1]’ ( beacues of “”).

    So changing the consturctor to the following may be appropriate.

    Also we need to include
    typeid determine sthe data type at runtime.

    What do you say?

  • Sergey

    “Some older compilers (eg. Visual Studio 6) have a bug where the definition of template class functions must be put in the same file as the template class is defined in. Thus, if the template class were defined in X.h, the function definitions would have to also go in X.h (not X.cpp). This issue should be fixed in most/all modern compilers.”

    No.It is still not implemented in most of compilers and you have to use inclusion model. See discussions on Stackoverflow.com:Why should the implementation and the declaration of a template class be in the same header file?[^]

  • Sergey

    Actually, the program will most likely pass the compilation, but linker will report an error implying there is no function definition(s).

  • the compile(r) won’t even compile it.

  • Ville K

    So fix last for-loop!
    1. check decrementing of nCount: remove additional “-” characters and “;”-character at the end of loop-definition
    2. consider to use “\t” instead of “t” for printing tabs

  • Gopal

    I have a question but not related to Template.

    A generic question. What i think is that there might be a lots of library available to ready made use of codes. Like the example code you have given for data holding array, for sorting, for minmax, for searching etc. Am i right?

    How do i know which are codes ready made available for use for these type of different tasks?

    These codes might sit in different types of libraries. But i am not sure. If it is so, i have to dig out libraries for these codes for what i want to achieve? Correct?

    • Alex

      If I’m understanding you correctly, you’re asking whether there are existing libraries that you can use to help write programs? If so, the answer is YES! The C++ standard library is the main one, and it has a ton of useful functionality in it. Beyond that, third-party libraries, such as Boost, SDL, and QT provide additional useful functionality that you can leverage. The internet is full of documentation on what’s in these libraries (once you know the name of them, so you can look them up).

  • Reaversword

    Is it possible to have a more-than-one templated type in a function?

    Something like this:

    This actually doesn’t works, but I hope the idea shows clear.

    • Reaversword

      Ok, I found the way, just replace the two template definitions with:

      template <typename T, typename S>

      (and add a ";" to "return y-x", I forgot that!).

      Sorry Alex, I’m putting you homework with my comments. I’ll try to ask, as usual, and public the answer if I find it.

  • Lokesh

    #typo
    "Templated classes are instanced in the same way templated functions are -- the compile stencils" --> compiler
    Same paragraph - “, the compile won’t even compile it.” --> compiler

  • Gocha

    Found a typo.

    You wrote: "Creating template classes is works pretty much identically to creating template functions"

    Should be: "Creating template classes works pretty much identically to creating template functions"

  • Graham L. Tasker

    Gioven the following simplified example :

    which fails to compile, how do you decalre a friend operator function for a templated class? I have tried other possible combinations, i.e. declareing the friend function as templated.

    • Alex

      Your operator== function needs to be declared as:

  • Graham L. Tasker

    Sorry about the typing error line 33 should read

  • Graham L. Tasker

    I have done what you suggested and obtain the following compiler errors:

    what do you suggest next?

  • Patrick Roncagliolo

    Hi Alex, I suggest you to update the last section with these useful informations:
    due to the compiler workflow, on most compilers template classes can’t be compiled in a ".h + .cpp" standard way. In fact, the compiler can’t know for which types it has to generate the appropriate classes from the template. Although this could be achieved with some tuning on compilers (such as looking forward the type that will be used during instantiation of a class template in other sources that are compiled together with the template itself), think about a way to compile and link successfully template classes in a project if they were collected in an already-compiled library… it’s considered very hard, (almost impossible in the standard way)! In fact the compiler hasn’t the sources of the template, and so it can’t instantiate the class properly. The prototype doesn’t suffice the needs of the compiler. Even the STL has the implementation code exposed in the headers or directly visible and available to the compiler, due to this reason. I’ll give you some links:
    http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file
    http://stackoverflow.com/questions/8752837/undefined-reference-to-template-class-constructor
    Here you can find a workaround, that consist in explicitly telling the compiler to generate a class for pre-determined types (but the template will work only with tat limited subset of types instead of all types).

  • SJ

    Hey Alex,

    I am receiving an error LNK2019 which apparently is very common with template classes after a bit of googling, but I am unable to find a solution to the problem I am having.

    *** UPDATE ***
    So I discovered the solution to my problem before I posted my question, but I’ll post it anyways in case someone else runs into the same problem. My original code was:

    which gave me the LNK2019 error. The solution to this was to actually include another

    INSIDE the class declaration, right before where I declared the function prototype for overloading the << operator, as follows:

    So I guess that line has to be included before the template class declaration, and ANYWHERE you have classname<T> used?

  • Darren

    That last section on template separation of header and source is wrong is it not? You cannot separate template function declaration from definition as the compiler has no idea of the type or class that is going to be used. The template essentially leaves a hole in the definition that is filled when we specify in an executable the concrete type or class we are going to use. At this point the compiler can then check things like the size of the type or class, and where necessary check it has the appropriate operators overloaded / defined. This can only be done when we specify that concrete type to fill the hole. In other words the language requires us to put the definition in the header file with the declaration so that the templates are filled only when we include the header in executable code.

  • Sheeplie

    Hey, why this?

    • Alex

      This causes the compiler to stencil out the class Array, which then gets compiled. Because functions are extern by default, references to these functions in other files will link to these.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter

  

  

  

twelve − 10 =