Search

13.3 — Template classes

In the previous two lessons, you learn how 13.1 -- Function templates, which get instantiated into 13.2 -- Function template instances, allow us 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 further do for us.

Templates and container classes

In the lesson on 10.6 -- 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 (int vs double). 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 our array class, templated 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

Template classes are instanced in the same way template functions are -- the compiler stencils out 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.

Template classes in the standard library

Now that we’ve covered template classes, you should understand what std::vector<int> means now -- std::vector is actually a template class, and int is the type parameter to the template! The standard library is full of predefined template classes available for your use. We’ll cover these in later chapters.

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 issue. However, there is one area that commonly causes problems for developers.

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)

In order for the compiler to use a template, it must see both the template definition (not just a declaration) and the template type used to instantiate the template. Also remember that C++ compiles files individually. When the Array.h header is #included in main, the template class definition is copied into main.cpp. When the compiler sees that we need two template instances, Array<int>, and Array<double>, it will instantiate these, and compile them as part of main.cpp. However, when it gets around to compiling Array.cpp separately, it will have forgotten that we need an Array<int> and Array<double>, so that template function is never instantiated. Thus, we get a linker error, because the compiler can’t find a definition for Array<int>::getLength() or Array<double>::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, below the class). 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 increase your compile and link times (your linker should remove the duplicate definitions, so it shouldn’t bloat your exectuable). This is our preferred solution unless the compile or link times start to become 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 template class. In the above case, the compiler will stencil out both Array<int> and Array<double> 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 for each program.

13.4 -- Template expression parameters
Index
13.2 -- Function template instances

38 comments to 13.3 — Template classes

  • 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?

    • Alex

      You could do as you suggest, or you could do a class template specialization for type char, or you could simply tell the users of the class to make sure that when they pass in the length, they need to account for any null-terminators. I’d probably just do the last one, as C-style arrays require specifying a size that includes the null terminator, so programmers would probably expect a class to adhere to the same assumptions.

  • 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.

  • 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

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

    what do you suggest next?

  • 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?

  • Sheeplie

    Hey, why this?

    • Alex

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

  • Kattencrack Kledge

    In the template class, when I want to overwrite the operator<< (that uses ostream), I get a linker error, and I don’t know what is wrong:

    Array.h

    Array.cpp

    Error: LNK2019 unresolved external symbol “class std::basic_ostream<char,struct std::char_traits > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits > &,class Array &)” (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Array@H@@@Z) referenced in function _main Chapter 12 I-O C:Users(…)Chapter 12 I-O.obj 1

    -------------

    Also, when I write all of my template class’ functions on a separate file, I always have to re-type template <typename T> for each functions. Is there a less redundant way to do it?

    Array.cpp

    • Alex

      Try putting your definition for operator<< in the header file.

      Yes, you have to put the template <typename T> ahead of every function. There’s no shortcut that I’m aware of. Just copy/paste it.

      • Kattencrack Kledge

        Putting my definition for operator<< will fix the problem, but what if I wanted to put it on a separate file. Is there any way to do that?

        • Alex

          You can either #include your .cpp file as well as the .h (not recommended) or use the three-file solution mentioned in the subsection above called “Splitting up template classes”.

  • Matt

    Before your first code example of the templated Array class, you wrote:
    " Here’s the IntArray classes, templatated version:".

    That doesn’t sound right to me. Did you mean to write something different there?

  • Matt

    In your 4th from last sentence, you wrote:
    " In the above case, the compiler will stencil out both Array and Array inside of templates.cpp."

    Did you mean "Array<int> and Array<double>"?

  • Dorian

    You said the easiest way is to put all of the template class code in the header file, but that will bloat our code if the template class is used in many places.
    Wont the (good) compiler optimize (remove) all the identical copies of the template class, and use always the same code?

    • Alex

      My understanding is that most compilers will happily compile multiple copies of the instantiated template class, and rely on the linker to remove the redundant definitions. So this would have the impact of increasing your compile and link times.

  • Ankit

    If I have a template class as follows:

    And then a specialize this class for a type say int"

    Now is there anyway I could use both the default template foo and the "specialized for int" foo?

    What I mean is if I don’t include the file where the int specialization is defined and template instantiate foo for int:

    Can I still print "Template class"

    • Alex

      Sure, if you don’t include the file where the specialization is defined, then your templated variable will use the generic version.

      • Ankit

        Thanks for your reply Alex. I am trying to test this scenario before making similar changes to my production code. So to sum it up, we can use the generic version of the template class in one compilation unit and the specialized version of the template class in a different compilation unit, both in the same program session. And this should not cause "multiple definition" linkage error?

        Also, where do you recommend learning template programming from?

        • Alex

          I’m not aware of any reason it would cause multiple definition linkage errors -- though I’d advise you to try and it and see for sure. 🙂

          Template programming really isn’t much different than normal programming outside of the crazy syntax and the parameterization of types. I don’t have any other specific resources I’d recommend for learning at this time, but I’m sure a quick google search would turn up plenty of other sites of interest.

  • Don Levin

    I’m using Visual Studio 2015 writing C++ 11 console app and a "static lib" I made having only a "function template" to return max value of two numbers.
    Solution: Moday
    Project #1: StaticLib
    Project #2: Top (has main program that calls ‘function template’ called GetMax)

    It builds, runs, and produces 11 as max of 9 and 11.  There’s only three files:  top.cpp, mylib.h, and mylib.cpp (which is empty).  

    If mylib.cpp is removed, Build fails to produce a lib.  
    Why?  
    Is there a Property setting to fix this (so that all template code can be in a header file, with no cpp file, and have it output a .lib file)?  

    I searched for weeks, and hate having dozens of empty cpp files in a large "real Solution" that uses existing code located in folders throughout the hard drive.

    >> I deleted Microsoft precompiled headers and fixed Project Properties to indicate No Precompiled headers in either Project.

    >> "Top Project" Property page has C/C++ > General > Additional Include

       Directories:  C:\Users\…\Monday\StaticLib  (path to mylib.h) No other changes to Property pages.

       Under Top: References, I added a Reference to StaticLib.

    There is only one Solution, called ‘Monday’.  There’s only two Projects:  StaticLib and Top.

    StaticLib Project:

    // mylib.h

    #ifndef MYLIB_H

    #define MYLIB_H

    #include <iostream>

    template <class myType>

    myType GetMax(myType a, myType b) {

      return (a>b ? a : b);

    }

    #endif // inc. guard…

    // mylib.cpp

    // empty!!

    Top Project:

    // top.cpp

    #include <iostream>

    #include "mylib.h"

    using namespace std;

    int main(){

      int i = 9;

      int j = 11;

      cout << GetMax(i, j) << endl;

       cout << "Done! Press Enter to exit…" << endl;

      cin.ignore();

    }

  • Don Levin

    1>---- Rebuild All started: Project: StaticLib, Configuration: Debug Win32 ----
    2>---- Rebuild All started: Project: Top, Configuration: Debug Win32 ----
    2>  top.cpp
    2>LINK : fatal error LNK1104: cannot open file ‘…MondayDebugStaticLib.lib’
    ========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

    The lib file doesn’t get made (and the previous .lib gets erased).

  • Don Levin

    I’ve read many such suggestions but they only address "simple" errors (like wrong path to lib).  VS fails to build a lib (I believe because MS designed it to require a cpp file even if empty), so obviously you get LNK1104.  Ignore this LNK error, and answer how to build a static lib Project  containing a function template that is called from a second Project under a Solution using MSVC 2015, without a "meaningless" (do nothing) cpp file.

  • Don Levin

    Thanks, I read this prior to posting above.  This is 7 years old, using VC++ different than 2015.  The ideas still apply: "template can’t be compiled into a library because it doesn’t know what the template will be. … you don’t actually need ANY library to be compiled or included if you distribute header files with template definition".  Others (like me) have said they have folders full of functions needed by Projects under many "Solutions".  Putting the functions into a lib allows them to be added as a group rather than like a giant list of files.  I posed this question to the msdn forum too but haven’t gotten an answer I like.  I’m asking them and you to try to build my code above (a few lines of code) and you’ll quickly see the problem.  Is an empty cpp file required, or is there a Property setting to tell the compiler "build a library like you do with an empty cpp file"?

Leave a Comment

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