Search

13.1 — Function templates

The need for function templates

In previous chapters, you’ve learned how to write functions and classes that help make programs easier to write, safer, and more maintainable. While functions and classes are powerful and flexible tools for effective programming, in certain cases they can also be somewhat limiting because of C++’s requirement that you specify the type of all parameters.

For example, let’s say you wanted to write a function to calculate the maximum of two numbers. You might do so like this:

This function would work great -- for integers. What happens later when you realize your max() function needs to work with doubles? Traditionally, the answer would be to overload the max() function and create a new version that works with doubles:

Note that the code for the implementation of the double version of maximum() is exactly the same as for the int version of max()! In fact, this implementation would work for all sorts of different types: chars, ints, doubles, and if you’ve overloaded the > operator, even classes! However, because C++ requires you to make your variables specific types, you’re stuck writing one function for each type you wish to use.

Having to specify different “flavors” of the same function where the only thing that changes is the type of the parameters can become a maintenance headache and time-waster, and it also violates the general programming guideline that duplicate code should be minimized as much as possible. Wouldn’t it be nice if we could write one version of max() that was able to work with parameters of ANY type?

Welcome to the world of templates.

What is a function template?

If you were to look up the word “template” in the dictionary, you’d find a definition that was similar to the following: “a template is a model that serves as a pattern for creating similar objects”. One type of template that is very easy to understand is that of a stencil. A stencil is an object (e.g. a piece of cardboard) with a shape cut out of it (eg. the letter J). By placing the stencil on top of another object, then spraying paint through the hole, you can very quickly produce stenciled patterns in many different colors! Note that you only need to create a given stencil once -- you can then use it as many times as you like, to create stenciled patterns in whatever color(s) you like. Even better, you don’t have to decide the color of the stenciled pattern you want to create until you decide to actually use the stencil.

In C++, function templates are functions that serve as a pattern for creating other similar functions. The basic idea behind function templates is to create a function without having to specify the exact type(s) of some or all of the variables. Instead, we define the function using placeholder types, called template type parameters. Once we have created a function using these placeholder types, we have effectively created a “function stencil”.

When you call a template function, the compiler “stencils” out a copy of the template, replacing the placeholder types with the actual variable types from the parameters in your function call! Using this methodology, the compiler can create multiple “flavors” of a function from one template! We’ll take a look at this process in more detail in the next lesson.

Creating function templates in C++

At this point, you’re probably wondering how to actually create function templates in C++. It turns out, it’s not all that difficult.

Let’s take a look at the int version of max() again:

Note that there are 3 places where specific types are used: parameters x, y, and the return value all specify that they must be integers. To create a function template, we’re going to replace these specific types with placeholder types. In this case, because we have only one type that needs replacing (int), we only need one template type parameter.

You can name your placeholder types almost anything you want, so long as it’s not a reserved word. However, in C++, it’s customary to name your template types the letter T (short for “Type”).

Here’s our new function with a placeholder type:

This is a good start -- however, it won’t compile because the compiler doesn’t know what “T” is!

In order to make this work, we need to tell the compiler two things: First, that this is a template definition, and second, that T is a placeholder type. We can do both of those things in one line, using what is called a template parameter declaration:

Believe it or not, that’s all we need. This will compile!

Now, let’s take a slightly closer look at the template parameter declaration. We start with the keyword template -- this tells the compiler that what follows is going to be a list of template parameters. We place all of our parameters inside angled brackets (<>). To create a template type parameter, use either the keyword typename or class. There is no difference between the two keywords in this context, so which you use is up to you. Note that if you use the class keyword, the type passed in does not actually have to be a class (it can be a fundamental variable, pointer, or anything else that matches). Then you name your type (usually “T”).

If the template function uses multiple template type parameter, they can be separated by commas:

For classes using more than one type, it’s common to see them named “T1” and “T2”, or other single capital letter names, such as “S”.

One final note: Because the function argument passed in for type T could be a class type, and it’s generally not a good idea to pass classes by value, it would be better to make the parameters and return types of our templated function const references:

Using function templates

Using a function template is extremely straightforward -- you can use it just like any other function. Here’s a full program using our template function:

This will print:

7
18.523
a

Note that all three of these calls to max() have parameters of different types! Because we’ve called the function with 3 different types, the compiler will use the template definition to create 3 different versions of this function: one with int parameters (named max<int>), one with double parameters (named max<double>), and one with char parameters (named max<char>).

Note that you don’t need to explicitly specify the template type in the function name (e.g. the <int> part of max<int>) so long as the compiler can deduce it from the parameter types.

Summary

As you can see, template functions can save a lot of time, because you only need to write one function, and it will work with many different types. Once you get used to writing function templates, you’ll find they actually don’t take any longer to write than functions with actual types. Template functions reduce code maintenance, because duplicate code is reduced significantly. And finally, template functions can be safer, because there is no need to copy functions and change types by hand whenever you need the function to work with a new type!

Template functions do have a few drawbacks, and we would be remiss not to mention them. First, some older compilers do not have very good template support. However, this downside is no longer as much of a problem as it used to be. Second, template functions often produce crazy-looking error messages that are much harder to decipher than those of regular functions (we’ll see an example of this in the next lesson). Third, template functions can increase your compile time and code size, as a single template might be “realized” and recompiled in many files (there are ways to work around this one).

However, these drawbacks are fairly minor compared with the power and flexibility templates bring to your programming toolkit!

Note: The standard library already comes with a templated max() function (in the algorithm header), so you don’t have to write your own (unless you want to). If you do write your own, note the potential for naming conflicts if you use the statement “using namespace std;”, as the compiler will be unable to tell whether you want your version of max() or std::max().

In the rest of this chapter, we’ll continue to explore the topic of templates.

13.2 -- Function template instances
Index
12.x -- Chapter 12 comprehensive quiz

80 comments to 13.1 — Function templates

  • zerocl

    my function is this:

    how can I declaration this function in header file class that is template <class T> ?

  • José Pedro

    Hi! Thanks for you great tutorial 🙂 I'm proud to be able to make this far, and I definitely owe that to you dear master!

    Although I got it on my own, I think you should say that the

    call on a templated function should actually be

    but since you're placing two integers on the parameters, the compiler implicitly knows you're asking for the

    .

    Otherwise it gets messy understanding why you make calls to templated classes like Array<int>... I personally didn't understand at first why you need to include <> on classes and not on functions 🙂

    Again thanks A LOT for your great tutorial! Thank you, thank you, thank you!

    • Alex

      Fair point. I amended the lesson. Thanks for the suggestion.

      For what it's worth, Bjarne Stroustrup was asked why we can omit providing explicit types for function calls but not for class templates. He said, "Note that class template arguments are never deduced. The reason is that the flexibility provided by several constructors for a class would make such deduction impossible in many cases and obscure in many more."

      • José Pedro

        Got it 🙂 I haven't played up too much with classes but I'm sure using many constructors should open a lot of possibilities, and it would look like template hell if types were to be deducted.

        I'm happy I was able to give a useful suggestion! Never thought I would ever be able to contribute (not even a little bit) for this amazing tutorials.

        Again thank you very much for such altruistic and amazing effort you're putting in here! I'm a teacher myself and I admire your teaching skills !

  • TC

    Hi Alex,

    Is Template in C++ similar to Generic in
    Java or C#?

    • I'm not all too familiar with Java and C#, but from what I know I'd say Java's generics are pretty similar. There's a list of differences to C# over at msdocs https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/differences-between-cpp-templates-and-csharp-generics

  • Winch

    Could you add some explanation about Template argument deduction?
    I have seen this topic in other websites and books, but not here.

    • Alex

      I'm not sure I understand the topic well enough to explain in a concise and conversational way. Let me add it to my to-do list.

      • Winch

        I can say that you are doing a great job here, everything looks simple and easy to understand.
        But, when I started this section, templates, I had the feeling that many details were missing.
        Maybe, those details are too complicated to add them here.
        I don´t know if I can cite other web-sites to give you some idea of what I am talking about.

        PD:Not native english speaker. Sorry if I have made mistakes.

        • Alex

          In some cases, those topics may be too complicated/obscure/advanced. In other cases, I may have not just got to them yet (particularly if they are new to C++14/17). If you have a list of topics that you'd like to see tutorials for, please drop me a line using the contact form in the about section. Thanks!

  • Jack

    When does the template parameter declaration go out of scope/become no longer accessible?

    I've noticed that

    Compiles and outputs:

    5
    2

    As expected. However,

    Fails to compile -- error: 'T' does not name a type. This is followed by a ''min' was not defined...' error, because of the invalid return type on min.

    This suggests to me that

    If this is correct:

    1) How does the compiler know that this is where to make it inaccessible?
    2) Is there any way to prolong the duration of the declaration so to save having to rewrite it everytime we want a template function? Taking the above as an example, we might have a few functions that we want templates for, and this would help to reduce the amount of code written?

    • Alex

      As far as I'm aware, the template parameter declaration is only scoped to the declaration/definition that immediately follows (meaning that your suggestion above is correct).

      I'm not aware of any way to change that, which can lead to a lot of redundant template declarations.

  • Adrian

    hey. I don't understand how the template function work with these parameters 3, 7. we defined our function parameter's types as const T& right? is this make sense that we pass const 3& and const 7& to the function?

    #include <iostream>

    template <typename T>
    const T& max(const T& x, const T& y)
    {
        return (x > y) ? x : y;
    }

    int main()
    {
        int i = max(3, 7); // returns 7
        std::cout << i << '\n';
            return 0;
    }

  • Adrian

    why this isn't a good idea to pass a class by value?

    • nascardriver

      Hi Adrian!

      Classes tend to have many member variables. All those variables have to be copied, which is a resource-hungry operation. Passing by reference copies the size of a pointer no matter how big the class is.

  • Chandra

    Hi Alex,

    This code is not working with string parameter not sure what is the issue.

    Can anyone give some insights over this issue.

    Thanks.

    [code]

    #include <bits/stdc++.h>

    using namespace std;

    template <class T>
    T  add(const T  a,const T  b){
       return a+b;
        
    }
        

    int main()
    {
      cout<< add(10,20)<<endl;     //Working Fine
      cout<< add(10.4,10.2)<<endl;  //Working Fine
    cout<<add("chandra ","shekhar")<<endl;//Giving me error....Not Sure what is the issue
        
        
        
        return 0;
    }
    [code]

    • Alex

      String literals are of type const char[], which is a const char pointer. Operator+ can not be used with two strings.

      You can make this work by making the strings std::string instead:

  • Chandra

    Hi Alex

    I am working with the code and tried here to make a generic add() to add any datatype. Bur not sure why it is giving me error when I am trying to use strings as parameter .

    Could you please help .

    #include <bits/stdc++.h>

    using namespace std;

    template <class T>
    T  add(const T  a,const T  b){
       return a+b;
        
    }
        

    int main()
    {
      cout<< add(10,20)<<endl;     //Working Fine
      cout<< add(10.4,10.2)<<endl;  //Working Fine
    cout<<add("chandra ","shekhar")<<endl;//Giving me error....Not Sure what is the issue
        
        
        
        return 0;
    }

    • nascardriver

      Hi Chandra!

      "chandra" and "shekhar" are not

      , they are

      and don't have operator+ defined.
      You need to explicitly instantiate your strings as @std::string or implement special treatments for const char * in @add using type traits or constexpr if.

      References
      * std::enable_if_t - http://en.cppreference.com/w/cpp/types/enable_if
      * constexpr if - http://en.cppreference.com/w/cpp/language/if

      • Chandra

        Hi nascardriver,
        Thanks a lot for the prompt response.
        I will try to implement as sughested by you.

        Thanks you

      • Adrian

        hey man. I tried to do it with type traits but ohh! that was complicated. I get the idea what is the use of type traits but I couldn't find some simple example of using it.(even though I searched in youtube and the other websites like cpprefrence). I will appreciate if you illustrate using enable_if with example or give me some reference to learn it.

        • nascardriver

          I feel your pain, type traits can be hard at times.
          Here's a working example, note that it return's an @std::string rather than a const char*, I find it easier than concatenating const char*s.

          • Adrian

            thank you for replying. I still don't understand line 5 cuz obviously I don't know how to work with type-traits library. can you give me some reference to learn it? how do you learn type traits?
            you know when you start learning a language everything is good, for every single concept or function
            there is tons of videos and stuff to help you and you keep going learning  but at some point you see there is not much tutorials or something to learn about something you want to learn(except some references that isn't really for learning I think these are useful for somebody that already knew the thing). what should to do at that point?

            • nascardriver

              Unfortunately I don't have any good tutorials for you. Every time I have trouble with type traits it takes me a while to figure out what's going on, because no matter where you look it up people will do it differently. There might be a good tutorial out there now, I haven't checked in a while.

              Line 5
              We start out with our templated function as usual.
              In addition to the two parameters of interest, we add a third parameter.
              std::enable_if_t returns the specified type (T) when the condition is met.
              If the condition is not met, the function is ill-formed and will be ignored during overload resolution (That's how all this works).
              We have two cases, either the condition is met, or it isn't. If it's met, the function is expanded to (sample with int)

              The last parameter is anonymous, because we're not going to use it anyway, and it defaults to a nullptr so we don't have to pass a real argument, but can use the function as if it had only two parameters.
              In case @T is a const char*, std::enable_if_t fails and the function is ignored. The other function is used instead.

              References
              * SFINAE, The feature that allows this to work - https://en.cppreference.com/w/cpp/language/sfinae
              * type_traits, An overview of all the type functions in <type_traits> - http://www.cplusplus.com/reference/type_traits/

  • Travis Touchdown

    Hi Alex,

    I tried implementing the code in the example "Using function templates". It didn't work when

    is in the code and works when the namespace code is not in the code. May I ask why?

    • Alex

      Not sure, as I wasn't able to reproduce this. Best guess is that the compiler is confused about whether max() means our user-defined max() function or std::max(), which is a function in the standard library.

  • Hi Alex,
    First of all - many thanks for your tutorial, genuinely thankful this exists.

    My question is: Whats the difference between the two?

    vs

    for the returned const T&, the ampersand is following the Type "T", but in the arguments doesn't it usually stand as a prefix to the input variable reference?

    Thank you, James

  • I could not understand in the third example.

    I expect ch should be 'b' in this situation, but why it is 'a'?
    [code]
        char ch = max('a', 'b'); // returns 'a'
        std::cout << ch << '\n';
    [\code]

    when we compare two chars, we are we actually comparing with?

    Does it compare two number, i.e. 97 & 98?

    If so, it should return 98,i.e. 'b'?

  • Bac Dang

    Hi mr Alex,
    I'm looking for "Thread" topic in this Tutorial, but i'm not find that.
    Do you have plan for writing about that?

    Thanks you !

  • simone

    Hi Alex, thank you for your excellent support.
    I was trying to make a function that assigns y to x regardless whether x, y are int or string. I wrote this code:

    But it doesn't work.
    It gives the error:

    at line 14:

    I can't understand, what is the problem?

    I know the objection: I might have just defined function assign as:

    which works. However, I was working on an other more complex function on which I have to (or at least I haven't found any way other than) use static_cast.

    So, if you could, please, explain to me what is the mistake in this example, I may try to fix the function I am working on.

    Thank you very much,
    Simone.

    • Alex

      When you call assign(a, b); with string parameters, the compiler creates a version of function assign() where T is a std::string. This means function parameters x and y are of type std:string.

      So consider this line of code:

      Since y is a std::string, you're trying to cast a std::string to an int, which is disallowed (even though this code should never run, the compiler still compiles it and does type checking to ensure everything is kosher).

      In actuality, all you should need to do here is assign a = b, and let the template functions do the work of handling the types:

  • Help

    Hello Alex,
    I got a off topic question. I downloaded visual studio as u showed in this site, i wanna learn program in .net as well. do i need to do something special to program in .net on visual studio or? how does it work?

    Thanks in advance!

    • Alex

      I'm not that familiar with .net, but I think you just need to install a .net enabled language (like C#) the same way you enabled Visual Studio for C++.

  • Hardik

    If the restriction of deducing the para-type of parameters gets lifted in future versions of C++ and We know the return-type can be deduced using the auto-keyword in C++, Won't the auto keyword work identically to templates ?
    Upto this point, I think 'YES'...
    What's Your Take On This?

    AND;
    One More Query :-
    Does the para-type of arguments passed to function also define the return-type of the function?
    For Eg :-

  • C++ Learner

    Hi Alex, can you explain why this code does not compile without making template and its arguments constant?

    • Alex

      Because your template parameters are defined as non-const references (which can only bind to l-values), but you're trying to call function max() with r-values. If you make max's x and y const, it should work.

  • Danny

    using code blocks, this is what i'm getting in the debugger

    error: call of overloaded 'max(int,int)' is ambiguous

    can i get some info on this

    • Alex

      You're probably having a naming conflict between your version of max and std::max. If you're using "using namespace std;" get rid of it.

  • The Long

    Hi, Alex.
    1. I try your example code with a little different in main() (same definition):

    The compiler does not compile due to the different types of parameters. Of course we can use multiple type of parameter in the declaration of the Template function, but I remember that there is a thing called implicit type conversion in C++. Does it not work here? If not, why is that?
    2. In "using function template" part, you passed argument by reference in the template function, how can you pass by value in main() ? I mean r-value which have no address. That code does not seem to work in Visual Studio 2012 Ultimate.
    Thank you for your time.

    • Alex

      1) Implicit type conversion doesn't work with template argument deduction. I'm not sure why that is. Maybe the matching rules would be too complex.
      2) Not by reference -- by const reference. Const references can bind to both l-values and r-values. If this doesn't work in Visual Studio 2012, then I'm surprised.

  • C

    Hi everyone,

      I have a question about "const T& ". In pointer, it is used as &T for the address of variable T. Why T& here?

    Thank you

    • Alex

      Here &T means a reference to T.

    • It's a reference. A third type of basic variable.

      Type 1, e.g. int,double,char,float...
      Type 2, pointer

      It is more safe to use reference because you need to initiate when you create it.

      You could also alia a variable using reference. It makes life easier.

      For example:

      If you use bash on a linux server, by alias a bunch of a command like: "alias project ='cd /YOUR/DIRECTORY/' ", you can just using a short name to ask computer do the same thing.

      That's the power of a reference.

      See more about reference:

      http://www.learncpp.com/cpp-tutorial/611-references/

  • Deepanshu

    Hi Alex, can you please help me to find out how can I sort out the error in the following C++ code containing a template?

    The error I am getting is in function ‘int main()’:
    error: call of overloaded ‘swap(int&, int&)’ is ambiguous
    error: call of overloaded ‘swap(float&, float&)’ is ambiguous

    • Alex

      Your user defined function swap() is having a naming conflict with standard library function std::swap() because you did a "using namespace std;". The compiler can't tell whether you intend to call your own swap function or std::swap.

      This is precisely why using explicit namespace prefixes is better than using namespace std.

    • Sinatra gunda

      • Hi Sinatra gunda:

        Although I tested your code, it works. It swapped a and b, but...

        Why you define your function in such a way that makes me hard to read?

        Instead of swap<>(&a,&b), why not just write a function like swap(a,b)?

    • Alex is right.

      [code]
      template <class X>
      void sswap( X &a, X &b) {
        X tp;
        tp = a;
        a = b;
        b = tp;
        cout << " Swapped elements values of a and b are  " << a << " and  " << b << " respectively " << endl;
      }

      int main( ) {
        int a = 10, b = 20 ;
        float c = 10.5, d = 20.5 ;
        sswap(a , b);          // function swapping ‘int’ elements                                                                                                                                    
        sswap(c , d);                  // function swapping ‘float’ elements                                                                                                                          
        return 0;
      }
      [\code]

      Just change the name of your function, it works!

  • YKT

    Do u have plan to provide the "Multi-Threading or Concurrency" tutorial?

    Best Regards

  • kris

    double max(double dX, double dY)
    {
        return (dX > dY) ? dX : dY;
    }

    You did a couple of these examples before like this and never showed the meaning. what is it for?

  • mslade

    It seems like template functions can violate encapsulation. In your max() example, client code needs to know that it uses the > operator, and that operator>(the_type, the_type) needs to be defined for it to work.

    Is there a way around this or am I just wrong?

    • Alex

      Yes, the client code does need to know that it uses operator> and that operator needs to be defined for the function to work. This doesn't violate encapsulation though, as the data of all the classes involved still stays protected from outside tampering.

  • Clarisse

    The person who writes n this blog must be really happy with happy feelings =)

  • Can you define these Template functions in seperate cpp files and have the definition in a .h file like normal functions?

    If i then use the GetArrayLength() function from my main.cpp, I get the following build errors:

    If I just define the function twice (once in my helper.cpp and once in my main.cpp), everything works as expected. Any idea what's wrong here?

    • Slice

      I'm running Microsoft Visual Studio 2008 Professional Edition, Version 9.0.21022.8 RTM with .NET Framework, Version 3.5 SP1, and I can confirm that it still doesn't allow you to split a template into the typical header and source file arrangement. In order to get templates to work in that environment, one must still code the entire template definition inside the header file :(.

      On the up side: my 1st linker error in the whole tutorial. W00!

      Oh, and great tutorial Alex (if you still read these). I even stopped reading the book I was reading on C++ about halfway through and totally moved onto this and even started doing some graphics work at the same time because the information presented here was so clear and concise albeit littered with "it's" when they should have been "its" :P. I will go back and finish the book at some point just in case I missed anything, but in the mean time onward I go.

      • Darren

        By-the-way this behaviour is correct. Think of the template as being a hole in the function definition that won't be filled until it is complied and linked with some usage of the function, i.e. in an executable; it won't compile otherwise as the compiler has no idea of the size of the type that is going to be used. The template definition must therefore reside in the header file so that it is compiled with an executable's source code when it is included. You can put template function declaration and template definition into separate files but have to include the file containing the definition at the bottom of the header file (technically the definition is then still in the header file). Typically the definition file has an '.inl' extension to differentiate them from normal source files.

        Because you have to include the template function definition in the header file this can significantly increase the time taken to compile large projects that rely on templated functions. However, most programmers are not overly concerned with compile times.

  • karmeloz

    when we use the keyword "template", we tell the compiler that what follows is going to be a list of template parameters.
    so why do we need the additional keyword typename (or class) for each parameter ? is the keyword typename redudantant
    or does it have a specific function? thanks, Karmeloz

  • Puneet

    Many people are not able to explain things in such a clear way.. This is really helpful.. Thanks...

  • Abhijit Yelegaonkar

Leave a Comment

Put all code inside code tags: [code]your code here[/code]