Chapter 1

Function Templates

This chapter introduces function templates. Function templates are functions that are parameterized so that they represent a family of functions.

1.1 A First Look at Function Templates

Function templates provide a functional behavior that can be called for different types. In other words, a function template represents a family of functions. The representation looks a lot like an ordinary function, except that some elements of the function are left undetermined: These elements are parameterized. To illustrate, let’s look at a simple example.

1.1.1 Defining the Template

The following is a function template that returns the maximum of two values:

basics/max1.hpp

template<typename T>
T max (T a, T b)
{
    // if b < a then yield a else yield b
    return b < a ? a : b;
}

This template definition specifies a family of functions that return the maximum of two values, which are passed as function parameters a and b.1 The type of these parameters is left open as template parameter T. As seen in this example, template parameters must be announced with syntax of the following form:

template< comma-separated-list-of-parameters >

In our example, the list of parameters is typename T. Note how the < and > tokens are used as brackets; we refer to these as angle brackets. The keyword typename introduces a type parameter. This is by far the most common kind of template parameter in C++ programs, but other parameters are possible, and we discuss them later (see Chapter 3).

Here, the type parameter is T. You can use any identifier as a parameter name, but using T is the convention. The type parameter represents an arbitrary type that is determined by the caller when the caller calls the function. You can use any type (fundamental type, class, and so on) as long as it provides the operations that the template uses. In this case, type T has to support operator < because a and b are compared using this operator. Perhaps less obvious from the definition of max() is that values of type T must also be copyable in order to be returned.2

For historical reasons, you can also use the keyword class instead of typename to define a type parameter. The keyword typename came relatively late in the evolution of the C++98 standard. Prior to that, the keyword class was the only way to introduce a type parameter, and this remains a valid way to do so. Hence, the template max() could be defined equivalently as follows:

template<class T>
T max (T a, T b)
{
    return b < a ? a : b;
}

Semantically there is no difference in this context. So, even if you use class here, any type may be used for template arguments. However, because this use of class can be misleading (not only class types can be substituted for T), you should prefer the use of typename in this context. However, note that unlike class type declarations, the keyword struct cannot be used in place of typename when declaring type parameters.

1.1.2 Using the Template

The following program shows how to use the max() function template:

basics/max1.cpp

#include "max1.hpp"
#include <iostream>
#include <string>
int main()
{
    int i = 42;
    std::cout << "max(7,i):      " << ::max(7,i) << ’\n’;

    double f1 = 3.4; double f2 = -6.7;
    std::cout << "max(f1,f2):    " << ::max(f1,f2) << ’\n’;

    std::string s1 = "mathematics"; std::string s2 = "math";
    std::cout << "max(s1,s2):    " << ::max(s1,s2) << ’\n’;
}

Inside the program, max() is called three times: once for two ints, once for two doubles, and once for two std::strings. Each time, the maximum is computed. As a result, the program has the following output:

max(7,i): 42
max(f1,f2): 3.4
max(s1,s2): mathematics

Note that each call of the max() template is qualified with ::. This is to ensure that our max() template is found in the global namespace. There is also a std::max() template in the standard library, which under some circumstances may be called or may lead to ambiguity.3

Templates aren’t compiled into single entities that can handle any type. Instead, different entities are generated from the template for every type for which the template is used.4 Thus, max() is compiled for each of these three types. For example, the first call of max()

int i = 42;
… max(7,i) …

uses the function template with int as template parameter T. Thus, it has the semantics of calling the following code:

int max (int a, int b)
{
    return b < a ? a : b;
}

The process of replacing template parameters by concrete types is called instantiation. It results in an instance of a template.5

Note that the mere use of a function template can trigger such an instantiation process. There is no need for the programmer to request the instantiation separately.

Similarly, the other calls of max() instantiate the max template for double and std::string as if they were declared and implemented individually:

double max (double, double);
std::string max (std::string, std::string);

Note also that void is a valid template argument provided the resulting code is valid. For example:

template<typename T>
T foo(T*)
{
}

void* vp = nullptr;
foo(vp);                            // OK: deduces void foo(void*)

1.1.3 Two-Phase Translation

An attempt to instantiate a template for a type that doesn’t support all the operations used within it will result in a compile-time error. For example:

std::complex<float> c1, c2;        // doesn’t provide operator <

::max(c1,c2);                     // ERROR at compile time

Thus, templates are “compiled” in two phases:

1. Without instantiation at definition time, the template code itself is checked for correctness ignoring the template parameters. This includes:

– Syntax errors are discovered, such as missing semicolons.

– Using unknown names (type names, function names, …) that don’t depend on template parameters are discovered.

– Static assertions that don’t depend on template parameters are checked.

2. At instantiation time, the template code is checked (again) to ensure that all code is valid. That is, now especially, all parts that depend on template parameters are double-checked.

For example:

template<typename T>
void foo(T t)
{
   undeclared();        // first-phase compile-time error if undeclared() unknown
   undeclared(t);        // second-phase compile-time error if undeclared(T) unknown
   static_assert(sizeof(int) > 10,          // always fails if sizeof(int)<=10
                 "int too small");
   static_assert(sizeof(T) > 10,            //fails if instantiated for T with size <=10
                 "T too small");
}

The fact that names are checked twice is called two-phase lookup and discussed in detail in Section 14.3.1 on page 249.

Note that some compilers don’t perform the full checks of the first phase.6 So you might not see general problems until the template code is instantiated at least once.

Compiling and Linking

Two-phase translation leads to an important problem in the handling of templates in practice: When a function template is used in a way that triggers its instantiation, a compiler will (at some point) need to see that template’s definition. This breaks the usual compile and link distinction for ordinary functions, when the declaration of a function is sufficient to compile its use. Methods of handling this problem are discussed in Chapter 9. For the moment, let’s take the simplest approach: Implement each template inside a header file.

1.2 Template Argument Deduction

When we call a function template such as max() for some arguments, the template parameters are determined by the arguments we pass. If we pass two ints to the parameter types T, the C++ compiler has to conclude that T must be int.

However, T might only be “part” of the type. For example, if we declare max() to use constant references:

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

and pass int, again T is deduced as int, because the function parameters match for int const&.

Type Conversions During Type Deduction

Note that automatic type conversions are limited during type deduction:

• When declaring call parameters by reference, even trivial conversions do not apply to type deduction. Two arguments declared with the same template parameter T must match exactly.

• When declaring call parameters by value, only trivial conversions that decay are supported: Qualifications with const or volatile are ignored, references convert to the referenced type, and raw arrays or functions convert to the corresponding pointer type. For two arguments declared with the same template parameter T the decayed types must match.

For example:

template<typename T>
T max (T a, T b);

int const c = 42;
max(i, c);            // OK: T is deduced as int
max(c, c);            // OK: T is deduced as int
int& ir = i;
max(i, ir);          // OK: T is deduced as int
int arr[4];
foo(&i, arr);        // OK: T is deduced as int*

However, the following are errors:

max(4, 7.2);        // ERROR: T can be deduced as int or double
std::string s;
foo("hello", s);    //ERROR: T can be deduced as char const[6] or std::string

There are three ways to handle such errors:

1. Cast the arguments so that they both match:

max(static_cast<double>(4), 7.2);        // OK

2. Specify (or qualify) explicitly the type of T to prevent the compiler from attempting type deduction:

max<double>(4, 7.2);                   // OK

3. Specify that the parameters may have different types.

Section 1.3 on page 9 will elaborate on these options. Section 7.2 on page 108 and Chapter 15 will discuss the rules for type conversions during type deduction in detail.

Type Deduction for Default Arguments

Note also that type deduction does not work for default call arguments. For example:

template<typename T>
void f(T = "");

f(1);        // OK: deduced T to be int, so that it calls f<int>(1)
f();         // ERROR: cannot deduce T

To support this case, you also have to declare a default argument for the template parameter, which will be discussed in Section 1.4 on page 13:

template<typename T = std::string>
void f(T = "");

f();        // OK

1.3 Multiple Template Parameters

As we have seen so far, function templates have two distinct sets of parameters:

1. Template parameters, which are declared in angle brackets before the function template name:

template<typename T>        // T is template parameter

2. Call parameters, which are declared in parentheses after the function template name:

T max (T a, T b)            // a and b are call parameters

You may have as many template parameters as you like. For example, you could define the max() template for call parameters of two potentially different types:

template<typename T1, typename T2>
T1 max (T1 a, T2 b)
{
    return b < a ? a : b; }

auto m = ::max(4, 7.2);        // OK, but type of first argument defines return type

It may appear desirable to be able to pass parameters of different types to the max() template, but, as this example shows, it raises a problem. If you use one of the parameter types as return type, the argument for the other parameter might get converted to this type, regardless of the caller’s intention. Thus, the return type depends on the call argument order. The maximum of 66.66 and 42 will be the double 66.66, while the maximum of 42 and 66.66 will be the int 66.

C++ provides different ways to deal with this problem:

• Introduce a third template parameter for the return type.

• Let the compiler find out the return type.

• Declare the return type to be the “common type” of the two parameter types.

All these options are discussed next.

1.3.1 Template Parameters for Return Types

Our earlier discussion showed that template argument deduction allows us to call function templates with syntax identical to that of calling an ordinary function: We do not have to explicitly specify the types corresponding to the template parameters.

We also mentioned, however, that we can specify the types to use for the template parameters explicitly:

template<typename T>
T max (T a, T b);

::max<double>(4, 7.2);        // instantiate T as double

In cases when there is no connection between template and call parameters and when template parameters cannot be determined, you must specify the template argument explicitly with the call. For example, you can introduce a third template argument type to define the return type of a function template:

template<typename T1, typename T2, typename RT>
RT max (T1 a, T2 b);

However, template argument deduction does not take return types into account,7 and RT does not appear in the types of the function call parameters. Therefore, RT cannot be deduced.8

As a consequence, you have to specify the template argument list explicitly. For example:

template<typename T1, typename T2, typename RT>
RT max (T1 a, T2 b);

::max<int,double,double>(4, 7.2);        // OK, but tedious

So far, we have looked at cases in which either all or none of the function template arguments were mentioned explicitly. Another approach is to specify only the first arguments explicitly and to allow the deduction process to derive the rest. In general, you must specify all the argument types up to the last argument type that cannot be determined implicitly. Thus, if you change the order of the template parameters in our example, the caller needs to specify only the return type:

template<typename RT, typename T1, typename T2>
RT max (T1 a, T2 b);

::max<double>(4, 7.2)        //OK: return type is double, T1 and T2 are deduced

In this example, the call to max<double> explicitly sets RT to double, but the parameters T1 and T2 are deduced to be int and double from the arguments.

Note that these modified versions of max() don’t lead to significant advantages. For the one-parameter version you can already specify the parameter (and return) type if two arguments of a different type are passed. Thus, it’s a good idea to keep it simple and use the one-parameter version of max() (as we do in the following sections when discussing other template issues).

See Chapter 15 for details of the deduction process.

1.3.2 Deducing the Return Type

If a return type depends on template parameters, the simplest and best approach to deduce the return type is to let the compiler find out. Since C++14, this is possible by simply not declaring any return type (you still have to declare the return type to be auto):

basics/maxauto.hpp

template<typename T1, typename T2>
auto max (T1 a, T2 b)
{
  return b < a ? a : b;
}

In fact, the use of auto for the return type without a corresponding trailing return type (which would be introduced with a -> at the end) indicates that the actual return type must be deduced from the return statements in the function body. Of course, deducing the return type from the function body has to be possible. Therefore, the code must be available and multiple return statements have to match.

Before C++14, it is only possible to let the compiler determine the return type by more or less making the implementation of the function part of its declaration. In C++11 we can benefit from the fact that the trailing return type syntax allows us to use the call parameters. That is, we can declare that the return type is derived from what operator?: yields:

basics/maxdecltype.hpp

template<typename T1, typename T2>
auto max (T1 a, T2 b) -> decltype(b<a?a:b)
{
  return b < a ? a : b;
}

Here, the resulting type is determined by the rules for operator ?:, which are fairly elaborate but generally produce an intuitively expected result (e.g., if a and b have different arithmetic types, a common arithmetic type is found for the result).

Note that

template<typename T1, typename T2>
auto max (T1 a, T2 b) -> decltype(b<a?a:b);

is a declaration, so that the compiler uses the rules of operator?: called for parameters a and b to find out the return type of max() at compile time. The implementation does not necessarily have to match. In fact, using true as the condition for operator?: in the declaration is enough:

template<typename T1, typename T2>
auto max (T1 a, T2 b) -> decltype(true?a:b);

However, in any case this definition has a significant drawback: It might happen that the return type is a reference type, because under some conditions T might be a reference. For this reason you should return the type decayed from T, which looks as follows:

basics/maxdecltypedecay.hpp

#include <type_traits>
template<typename T1, typename T2>
auto max (T1 a, T2 b) -> typename std::decay<decltype(true?a:b)>::type
{ return b < a ? a : b;
}

Here, the type trait std::decay<> is used, which returns the resulting type in a member type. It is defined by the standard library in <type_trait> (see Section D.5 on page 732). Because the member type is a type, you have to qualify the expression with typename to access it (see Section 5.1 on page 67).

Note that an initialization of type auto always decays. This also applies to return values when the return type is just auto. auto as a return type behaves just as in the following code, where a is declared by the decayed type of i, int:

int i = 42;
int const& ir = i;        // ir refers to
i auto a = ir;            // a is declared as new object of type int

1.3.3 Return Type as Common Type

Since C++11, the C++ standard library provides a means to specify choosing “the more general type.” std::common_type<>::type yields the “common type” of two (or more) different types passed as template arguments. For example:

basics/maxcommon.hpp

#include <type_traits>
template<typename T1, typename T2>
std::common_type_t<T1,T2> max (T1 a, T2 b)
{
  return b < a ? a : b;
}

Again, std::common_type is a type trait, defined in <type_traits>, which yields a structure having a type member for the resulting type. Thus, its core usage is as follows:

typename std::common_type<T1,T2>::type        //since C++11

However, since C++14 you can simplify the usage of traits like this by appending _t to the trait name and skipping typename and ::type (see Section 2.8 on page 40 for details), so that the return type definition simply becomes:

std::common_type_t<T1,T2>                    // equivalent since C++14

The way std::common_type<> is implemented uses some tricky template programming, which is discussed in Section 26.5.2 on page 622. Internally, it chooses the resulting type according to the language rules of operator ?: or specializations for specific types. Thus, both ::max(4, 7.2) and ::max(7.2, 4) yield the same value 7.2 of type double. Note that std::common_type<> also decays. See Section D.5 on page 732 for details.

1.4 Default Template Arguments

You can also define default values for template parameters. These values are called default template arguments and can be used with any kind of template.9 They may even refer to previous template parameters.

For example, if you want to combine the approaches to define the return type with the ability to have multiple parameter types (as discussed in the section before), you can introduce a template parameter RT for the return type with the common type of the two arguments as default. Again, we have multiple options:

1. We can use operator?: directly. However, because we have to apply operator?: before the call parameters a and b are declared, we can only use their types:

basics/maxdefault1.hpp

#include <type_traits>
template<typename T1, typename T2,
         typename RT = std::decay_t<decltype(true ? T1() : T2())>>
RT max (T1 a, T2 b)
{
  return b < a ? a : b;
}

Note again the usage of std::decay_t<> to ensure that no reference can be returned.10

Note also that this implementation requires that we are able to call default constructors for the passed types. There is another solution, using std::declval, which, however, makes the declaration even more complicated. See Section 11.2.3 on page 166 for an example.

2. We can also use the std::common_type<> type trait to specify the default value for the return type:

basics/maxdefault3.hpp

#include <type_traits>

template<typename T1, typename T2,
         typename RT = std::common_type_t<T1,T2>>
RT max (T1 a, T2 b)
{
  return b < a ? a : b;
}

Again, note that std::common_type<> decays so that the return value can’t become a reference.

In all cases, as a caller, you can now use the default value for the return type:

auto a = ::max(4, 7.2);

or specify the return type after all other argument types explicitly:

auto b = ::max<double,int,long double>(7.2, 4);

However, again we have the problem that we have to specify three types to be able to specify the return type only. Instead, we would need the ability to have the return type as the first template parameter, while still being able to deduce it from the argument types. In principle, it is possible to have default arguments for leading function template parameters even if parameters without default arguments follow:

template<typename RT = long, typename T1, typename T2>
RT max (T1 a, T2 b)
{
  return b < a ? a : b;
}

With this definition, for example, you can call:

int i; long l;

max(i, l);              // returns long (default argument of template parameter for return type)
max<int>(4, 42);        // returns int as explicitly requested

However, this approach only makes sense, if there is a “natural” default for a template parameter. Here, we need the default argument for the template parameter to depend from previous template parameters. In principle, this is possible as we discuss in Section 26.5.1 on page 621, but the technique depends on type traits and complicates the definition.

For all these reasons, the best and easiest solution is to let the compiler deduce the return type as proposed in Section 1.3.2 on page 11.

1.5 Overloading Function Templates

Like ordinary functions, function templates can be overloaded. That is, you can have different function definitions with the same function name so that when that name is used in a function call, a C++ compiler must decide which one of the various candidates to call. The rules for this decision may become rather complicated, even without templates. In this section we discuss overloading when templates are involved. If you are not familiar with the basic rules of overloading without templates, please look at Appendix C, where we provide a reasonably detailed survey of the overload resolution rules.

The following short program illustrates overloading a function template:

basics/max2.cpp

// maximum of two int values:
int max (int a,
int b)
{
  return b < a ? a : b;
}
// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
  return b < a ? a : b;
}

int main()
{
  ::max(7, 42);                // calls the nontemplate for two ints
  ::max(7.0, 42.0);            // calls max<double> (by argument deduction)
  ::max(’a’, ’b’);              //calls max<char> (by argument deduction)
  ::max<>(7, 42);              // calls max<int> (by argument deduction)
  ::max<double>(7, 42);        // calls max<double> (no argument deduction)
  ::max(’a’, 42.7);             //calls the nontemplate for two ints
}

As this example shows, a nontemplate function can coexist with a function template that has the same name and can be instantiated with the same type. All other factors being equal, the overload resolution process prefers the nontemplate over one generated from the template. The first call falls under this rule:

::max(7, 42);        // both int values match the nontemplate function perfectly

If the template can generate a function with a better match, however, then the template is selected. This is demonstrated by the second and third calls of max():

::max(7.0, 42.0);        // calls the max<double> (by argument deduction)
::max(’a’, ’b’);          //calls the max<char> (by argument deduction)

Here, the template is a better match because no conversion from double or char to int is required (see Section C.2 on page 682 for the rules of overload resolution).

It is also possible to specify explicitly an empty template argument list. This syntax indicates that only templates may resolve a call, but all the template parameters should be deduced from the call arguments:

::max<>(7, 42);        // calls max<int> (by argument deduction)

Because automatic type conversion is not considered for deduced template parameters but is considered for ordinary function parameters, the last call uses the nontemplate function (while ’a’ and 42.7 both are converted to int):

::max(’a’, 42.7);        //only the nontemplate function allows nontrivial conversions

An interesting example would be to overload the maximum template to be able to explicitly specify the return type only:

basics/maxdefault4.hpp

template<typename T1, typename T2>
auto max (T1 a, T2 b)
{
  return b < a ? a : b;
}
template<typename RT, typename T1, typename T2>
RT max (T1 a, T2 b)
{
  return b < a ? a : b;
}

Now, we can call max(), for example, as follows:

auto a = ::max(4, 7.2);                     // uses first template
auto b = ::max<long double>(7.2, 4);        // uses second template

However, when calling:

auto c = ::max<int>(4, 7.2);                // ERROR: both function templates match

both templates match, which causes the overload resolution process normally to prefer none and result in an ambiguity error. Thus, when overloading function templates, you should ensure that only one of them matches for any call.

A useful example would be to overload the maximum template for pointers and ordinary C-strings:

basics/max3val.cpp


#include   <cstring>
#include   <string>

// maximum of two values of any type:
template<typename    T>
T max (T a, T b)
{
   return      b < a ? a : b;
}

// maximum of two pointers:
template<typename    T>
T* max (T* a, T* b)
{
   return       *b < *a   ? a : b;
}

// maximum of two C-strings:
char const* max (char   const* a,   char const* b)
{
   return       std::strcmp(b,a) < 0   ? a : b;
}

int   main ()
{
   int a = 7;
   int b = 42;
   auto m1 = ::max(a,b);         // max() for two values of type int

   std::string s1 =   "hey"; "
   std::string s2 =   "you"; "
   auto m2 = ::max(s1,s2);       // max() for two values of type std::string

   int* p1 = &b;
   int* p2 = &a;
   auto m3 = ::max(p1,p2);       // max() for two pointers

   char const* x =  hello"; "
   char const* y =  "world"; "
   auto m4 = ::max(x,y);         // max() for two C-strings
}

Note that in all overloads of max() we pass the arguments by value. In general, it is a good idea not to change more than necessary when overloading function templates. You should limit your changes to the number of parameters or to specifying template parameters explicitly. Otherwise, unexpected effects may happen. For example, if you implement your max() template to pass the arguments by reference and overload it for two C-strings passed by value, you can’t use the three-argument version to compute the maximum of three C-strings:

basics/max3ref.cpp

#include <cstring>

// maximum of two values of any type (call-by-reference)
template<typename
T> T const& max (T const& a, T const& b)
{
  return b < a ? a : b;
}
// maximum of two C-strings (call-by-value)
char const* max (char const* a, char const* b)
{
  return std::strcmp(b,a) < 0 ? a : b;
}

// maximum of three values of any type (call-by-reference)
template<typename T>
T const& max (T const& a, T const& b, T const& c)
{
  return max (max(a,b), c);
            // error if max(a,b) uses call-by-value
}
int main ()
{
    auto m1 = ::max(7, 42, 68);        // OK
    char const* s1 = "frederic";
    char const* s2 = "anica";
    char const* s3 = "lucas";
    auto m2 = ::max(s1, s2, s3);       //run-time ERROR
}

The problem is that if you call max() for three C-strings, the statement

return max (max(a,b), c);

becomes a run-time error because for C-strings, max(a,b) creates a new, temporary local value that is returned by reference, but that temporary value expires as soon as the return statement is complete, leaving main() with a dangling reference. Unfortunately, the error is quite subtle and may not manifest itself in all cases.11

Note, in contrast, that the first call to max() in main() doesn’t suffer from the same issue. There temporaries are created for the arguments (7, 42, and 68), but those temporaries are created in main() where they persist until the statement is done.

This is only one example of code that might behave differently than expected as a result of detailed overload resolution rules. In addition, ensure that all overloaded versions of a function are declared before the function is called. This is because the fact that not all overloaded functions are visible when a corresponding function call is made may matter. For example, defining a three-argument version of max() without having seen the declaration of a special two-argument version of max() for ints causes the two-argument template to be used by the three-argument version:

basics/max4.cpp

#include <iostream>

// maximum of two values of any type:
template<typename T>
T max (T a, T b)
{
  std::cout << "max<T>() \n";
  return b < a ? a : b;
}

// maximum of three values of any type:
template<typename T>
T max (T a, T b, T c)
{
  return max (max(a,b), c);          // uses the template version even for ints
}                                    //because the following declaration comes
                                   // too late:

// maximum of two int values:
int max (int a,
int b)
{
  std::cout << "max(int,int) \n";
  return b < a ? a : b;
}

int main()
{
  ::max(47,11,33);        // OOPS: uses max<T>() instead of max(int,int)
}

We discuss details in Section 13.2 on page 217.

1.6 But, Shouldn’t We …?

Probably, even these simple function template examples might raise further questions. Three questions are probably so common that we should discuss them here briefly.

1.6.1 Pass by Value or by Reference?

You might wonder, why we in general declare the functions to pass the arguments by value instead of using references. In general, passing by reference is recommended for types other than cheap simple types (such as fundamental types or std::string_view), because no unnecessary copies are created.

However, for a couple of reasons, passing by value in general is often better:

• The syntax is simple.

• Compilers optimize better.

• Move semantics often makes copies cheap.

• And sometimes there is no copy or move at all.

In addition, for templates, specific aspects come into play:

• A template might be used for both simple and complex types, so choosing the approach for complex types might be counter-productive for simple types.

• As a caller you can often still decide to pass arguments by reference, using std::ref() and std::cref() (see Section 7.3 on page 112).

• Although passing string literals or raw arrays always can become a problem, passing them by reference often is considered to become the bigger problem. All this will be discussed in detail in Chapter 7. For the moment inside the book we will usually pass arguments by value unless some functionality is only possible when using references.

1.6.2 Why Not inline?

In general, function templates don’t have to be declared with inline. Unlike ordinary noninline functions, we can define noninline function templates in a header file and include this header file in multiple translation units.

The only exception to this rule are full specializations of templates for specific types, so that the resulting code is no longer generic (all template parameters are defined). See Section 9.2 on page 140 for more details.

From a strict language definition perspective, inline only means that a definition of a function can appear multiple times in a program. However, it is also meant as a hint to the compiler that calls to that function should be “expanded inline”: Doing so can produce more efficient code for certain cases, but it can also make the code less efficient for many other cases. Nowadays, compilers usually are better at deciding this without the hint implied by the inline keyword. However, compilers still account for the presence of inline in that decision.

1.6.3 Why Not constexpr?

Since C++11, you can use constexpr to provide the ability to use code to compute some values at compile time. For a lot of templates this makes sense.

For example, to be able to use the maximum function at compile time, you have to declare it as follows:

basics/maxconstexpr.hpp

template<typename T1, typename T2>
constexpr auto max (T1 a, T2 b)
{
  return b < a ? a : b;
}

With this, you can use the maximum function template in places with compile-time context, such as when declaring the size of a raw array:

int a[::max(sizeof(char),1000u)];

or the size of a std::array<>:

std::array<std::string, ::max(sizeof(char),1000u)> arr;

Note that we pass 1000 as unsigned int to avoid warnings about comparing a signed with an unsigned value inside the template.

Section 8.2 on page 125 will discuss other examples of using constexpr. However, to keep our focus on the fundamentals, we usually will skip constexpr when discussing other template features.

1.7 Summary

• Function templates define a family of functions for different template arguments.

• When you pass arguments to function parameters depending on template parameters, function templates deduce the template parameters to be instantiated for the corresponding parameter types.

• You can explicitly qualify the leading template parameters.

• You can define default arguments for template parameters. These may refer to previous template parameters and be followed by parameters not having default arguments.

• You can overload function templates.

• When overloading function templates with other function templates, you should ensure that only one of them matches for any call.

• When you overload function templates, limit your changes to specifying template parameters explicitly.

• Ensure the compiler sees all overloaded versions of function templates before you call them.

1 Note that the max() template according to [StepanovNotes] intentionally returns “b < a ? a : b” instead of “a < b ? b : a” to ensure that the function behaves correctly even if the two values are equivalent but not equal.

2 Before C++17, type T also had to be copyable to be able to pass in arguments, but since C++17 you can pass temporaries (rvalues, see Appendix B) even if neither a copy nor a move constructor is valid.

3 For example, if one argument type is defined in namespace std (such as std::string), according to the lookup rules of C++, both the global and the max() template in std are found (see Appendix C).

4 A “one-entity-fits-all” alternative is conceivable but not used in practice (it would be less efficient at run time). All language rules are based on the principle that different entities are generated for different template arguments.

5 The terms instance and instantiate are used in a different context in object-oriented programming—namely, for a concrete object of a class. However, because this book is about templates, we use this term for the “use” of templates unless otherwise specified.

6 For example, The Visual C++ compiler in some versions (such as Visual Studio 20133 and 2015) allow undeclared names that don’t depend on template parameters and even some syntax flaws (such as a missing semicolon).

7 Deduction can be seen as part of overload resolution—a process that is not based on selection of return types either. The sole exception is the return type of conversion operator members.

8 In C++, the return type also cannot be deduced from the context in which the caller uses the call.

9 Prior to C++11, default template arguments were only permitted in class templates, due to a historical glitch in the development of function templates.

10 Again, in C++11 you had to use typename std::decay<>::type instead of std::decay_t<> (see Section 2.8 on page 40).

11 In general, a conforming compiler isn’t even permitted to reject this code.