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 executable). 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

60 comments to 13.3 — Template classes

  • C++ Learner

    why there is a need to write <int> or <double> in these lines?

  • C++ Learner

    when class object is created erase function is called by itself?

  • Hi, in the "Splitting up Template Classes" section, Array.cpp has 2 misspellings - getLength (G is uppercase) and m_length (it is written there as m_nLength).
    Thanks as always.

  • CJ

    Hi Alex,

    Thank you very much for a great tutorial!! Really appreciate it !

    I had a question regarding

    shouldn’t this actually be,

    since m_data is a pointer ?

    • Alex

      Either works, but nullptr better reflects the intent. I’ll update the lesson. Thanks!

      • CJ

        Hi Alex,

        Could you please suggest some resources to learn multi threading in c++ ?

        Thank you

        • Alex

          I’m not aware of any good multi-threading tutorials, mostly because I haven’t looked recently. My advice is to do a google search and read stuff until you find something that is written for your level of technical comprehension.

  • Dekasi

    Hi Alex.
    I have a problem with the following program. How we should write the definition of the constructor (it has to be outside of the class)?

    indexList.h

    Main.cpp

  • Daniel

    Typo: should be "executable" in "shouldn’t bloat your exectuable"

  • Cecy Reigns

    hi Alex! Maybe I’m wrong but when you wrote the class DoubleArray, in the private section you put "double m_length;" shouldn’t be always "int m_length"?

  • Mauricio Mirabetti

    Dear Alex,
    On the sentence "Each templated member function declared outside the class declaration needs its own template declaration.", did you mean "function defined" instead of "declared"? You’re referring to the need of a template declaration right before function definition, right? Not sure if it’s a typo, or I misunderstood it.

    Best regards.

    Mauricio

    • Alex

      No, I did mean declared, because this applies to template function forward declarations as well as full template function definitions (which are both definitions and declarations).

  • Vivian

    For the 3 files solution mentioned at the end, would it be acceptable to instantiate the template classes inside Array.cpp rather than templates.cpp?

    • Alex

      You could. But then you’d need to modify Array.cpp for every program, which you probably don’t want to do (you want to write it once, and use it over and over without touching it).

  • John

    what is the point of the three files and the include .cpp file approach if we are going to include .cpp file, isn’t the compiler gonna compile it and since it was included then it is copied in another file" also compile" this way it is gonna be compiled twice, we dont we do all the code in the .h file, I’m confused ??? thanks

    • John

      why dont we do all the code in the .h file **

      • Alex

        You can, that’s the recommended solution. However, some people like to keep their declarations in the .h and definitions in the .cpp, and this provides a solution for doing so.

        There shouldn’t be any issues with the 3 file solution -- templates don’t get instantiated unless needed. So a .cpp file full of template definitions won’t get turned into any code if compiled by itself (since nobody is using it).

        In the three-file solution, we avoid this issue by explicitly including the .cpp file and putting it in the same place as where it’s needed, so the compiler knows to instantiate the template classes and compile them.

  • Sid

    Minor typo maybe.
    Above in the definition of class DoubleArray, line 22:

    m_data = new int[length];

    Isn’t it supposed to be:

    m_data = new double[length];

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

  • 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

    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’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();

    }

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

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

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

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

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

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

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

  • Graham L. Tasker

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

    what do you suggest next?

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

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

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

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

Leave a Comment

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