Templates in C++

Ever wondered how C++ handles code that works across multiple data types without rewriting functions or classes? The C++ templates are very efficient for generic programming, which is often misunderstood. But, are the templates better than function overloading, or do they come with hidden limitations? In this article, we’ll check out C++ function templates, class templates, template specialisation, and more, that even experienced developers often overlook.

Table of Contents:

What is a Template in C++?

In C++, templates are a powerful feature enabling generic and reusable code. Instead of writing redundant functions or classes for added data types, you can simply write a single template that works for all kinds. This enables code reuse, type safety, and clean design.

Template Variables

The template variables were introduced in C++14. These template variables are allowed to define the variables by type. Like functions or classes, the template variables are useful for constants that vary by type, like pi<T>.  

Example: 

Cpp

Output: 

Template Variables

The code introduces a constexpr template variable pi<T> containing the value of pi. It casts to the type requested (float, double…), to offer a compile-time evaluation with a given precision. If you use the main() using the pi<float>, you’ll get a less precise value because a float has less precision, but you will keep more decimal places when using pi<double>.

How Do Templates Work?

Templates are a blueprint that the compiler uses to generate the code for the specific data type at the use site. This is known as template instantiation. The compiler substitutes the template type parameters with actual ones during compile time.

Example: 

Cpp

Output: 

How Do Templates Work?

The above C++ program uses a template that takes two parameters of the same data type and returns their sum. However, the main function automatically displays how the template adapts based on the types. 

Types of Templates in C++

There are two types of templates in C++: 

1. Function Templates

Function templates allow you to write a single function to work with different data types. To declare this template, use template <typename T> before the declaration. 

Example:

Cpp

Output: 

1. Function Templates

This C++ program demonstrates a function template, maxVal, that returns the maximum of two values of any data type. The comparison uses the ternary operator to evaluate the two inputs and return the larger of the two. The main function demonstrates this with both integer and double values, highlighting the power of templates.

2. Class Templates

Class templates mean that you could define classes that work with any data type, making your classes reusable and generic.

Example: 

Cpp

Output: 

2. Class Templates

The output displays the values stored in the Box objects. It prints Value: 10 for the integer and Value: Template for the string.

C++ Template Parameters

When C++ template parameters are used, templates can be written to accept types or values as parameters to template functions, as such, for generic programming in a generic programming language. There are two primary kinds of template parameters, type parameters and non-type parameters. The keyword typename or class is used to denote type parameters, where the template can accept any parameter type. Non-type parameters can take on constant values, such as integers, pointers, or references, allowing for customisation linked to values known at compile-time.

Example: 

Cpp

Output: 

C++ Template Parameters

Here is a C++ code that shows a class template Array with type (T) and non-type (size) parameters. The superclass Arrays can create array objects of any size and type, with size determined at compile-time via a non-type template parameter. The main() function creates two arrays, one for integers and another for doubles, and assigns values.

Non-Typed Template Parameters

Non-type template parameters are the second type of template parameters. They can be integers, pointers, or references. Such constants are resolved at compile time and can be used to customise behaviour based on array sizes or specific constants. This enables more efficient and flexible code, since the compiler can optimise for these constant values.

Example: 

Cpp

Output: 

Non-Typed Template Parameters

The following C++ program shows a class template Array accepting two parameters: A type T and a non-type integer size indicating the array size. This example has the set() method to set values in the array and the show() method to print them. This program creates two Array objects with different sizes and types inside the main() function, showing how you can customise them using non-typed template parameters for size.

Standard Template Library in C++

STL is a collection based on templates and comprises a set of generic classes and functions. It consists of containers (such as vectors, maps), algorithms (such as sort, find), and iterators. It generates type-safe, efficient, and reusable code. The greatest strength of C++ is its STL.

Example:

Cpp

Output: 

Standard Template Library in C++

This code constructs a vector of integers, and then sorts them in ascending order (using std::sort), and outputs the sorted items. The result will be 1 2 4 5. 

Template Utilities

Some of the advanced template concepts in C++: 

1. Template Metaprogramming

Template metaprogramming(TMP)  is the use of templates to compute something during compile time. It leverages the compiler to compile derived logic into an optimised code. Simple for constant expressions such as factorials, primes, or type traits. Used in STL internals and Boost Libraries.

Example: 

Cpp

Output: 

1. Template Metaprogramming

The above code uses template metaprogramming to demonstrate the recursion usage in the factorial of a number at compile time. At first, the template recursively multiplies N by factorial<N-1>:: value. However, the specialised template for factorial<0> provides the base case by returning 1. By following the same, the factorial<5>:: value gives 120 (5*4*3*2*1). 

2. Variadic Templates

Functions or classes that can accept a variable number of template arguments are called variadic templates. They can be found in formatting, tuple unpacking, and forwarding, introduced in C++11. They depend on parameter pack recursion. Elegant and efficient for generic programming.

Example: 

Cpp

Output: 

2. Variadic Templates

The above code uses a Vardiac template to demonstrate the recursive print function, where it prints each argument followed by a space. The base case print() stops the recursion, and the main() function prints the passed values.  

3. Template Identifiers

Template identifiers explicitly refer to templates when working with template parameters, especially when defining or specializing templates, or when naming member templates. In certain contexts, the template keyword is required to indicate that a name refers to a template rather than a regular type or function. This is crucial when dealing with dependent names inside templates.

Example: 

Cpp

Output: 

3. Template Identifiers

This is an example that calls a templated method from a templated context with the template keyword to qualify a dependent name. The callShow function is involved in the Wrap object, hence it produces the value.

4. Templated Entity

A templated entity is a function, a class, or a variable defined by using templates. During compilation, these are monomorphized to certain types, with specific entities being instantiated. They allow the repeated logic between types. Entities can be template functions, classes, aliases, and variables.

Example: 

Cpp

Output:

4. Templated Entity

This code creates a generic add function with templates to add two values of the same type. In main(), it shows type-specific calls with int and double, printing out 7 and 5.0.

Can There Be More Than One Argument for Templates?

Yes, in C++, templates are permitted to take several arguments, in case of types and non-type parameters. It allows you to create more flexible and reusable code by allowing multiple combinations of different types or values in a single template. By using multiple type parameters, you can create classes or functions that work with multiple data types simultaneously, making your code more versatile and adaptable to different scenarios.

Example: 

Cpp

Output:

Can There Be More Than One Argument for Templates

Implementing a function template to display values of different types using templates with two different type parameters. It provides a demonstration of the power of templates for mixed-type input without writing special-case functions. The main function shows how to use it with an integer-string and a double-integer pair.

Can We Specify a Default Value for Template Arguments?

Yes, C++ lets you define default types for template parameters for the sake of more flexibility and brevity. If the user does not give a type argument, the compiler automatically picks the default. This is useful for designing general-purpose templates while still providing sensible defaults for your everyday cases.

Example: 

Cpp

Output: 

Can We Specify a Default Value for Template Arguments

This program defines a class template Number, which has a default template argument of int. When no type is provided (with Number), it defaults to int, but users can also specify float. The main function demonstrates both usages, printing values appropriately.

Get 100% Hike!

Master Most in Demand Skills Now!

Difference Between Function Overloading and Templates

Function overloading allows creating multiple functions with the same name, just varying the types or number of parameters. It is also type safe, as each function only takes a certain variety. 

Now, templates take type parameters, which means that one function/class can work with any type of data, making the code more flexible and reusable without the creation of numerous overloads. In contrast to the overload resolution that happens at runtime, based on the types of the arguments, templates are resolved during compile time with the types given for their arguments, resulting in more generalised solutions.

Example: 

Cpp

Output: 

Difference Between Function Overloading and Templates

This program shows the concept of Function overloading, with two add functions, one for int and the other for double. It also demonstrates a template function, addT, that works with any type, so long as both parameters are the same type. The main function tests both approaches and shows that templates typically provide greater flexibility at the expense of fewer function definitions.

What Happens When There Is a Static Member in a Template?

A static member of a template class is shared among all instances of the same type, but is separate for different template instantiations. In other words, a separate, initialised version of the static member will be created for each instantiation of a template class (e.g., Counter and Counter) that defines the member. This enables static variables on the type level that are unique to each template specialisation.

Example: 

Cpp

Output: 

What Happens When There Is a Static Member in a Template

The code demonstrates a template class Counter with a static member count that tracks the number of instances of the class for each type. Each time a Counter object is created, the constructor increments count. Static members are defined outside the class template. The program shows the count for different template types (int and float).

Template Specialization

The specialization allows for fine-tuned behaviour whenever a certain type is being used, while the general template can work with a whole variety of them. This is useful when a particular data type's default logic is neither efficient nor correct.

Example: 

Cpp

Output: 

Template specialization

Template specialization helps to change the template functionality according to a special type. The generic template will take care of all types, while the specialization will overtake it in some cases. This is useful when specific types require custom logic for correctness or performance.

Template Argument Deduction

Function template argument deduction (also known as argument deduction) is a feature of C++ where the compiler automatically deduces the template arguments for a function template based on the arguments passed in the function call. That means you don’t always have to specify the template type explicitly. C++ can infer it from the types that you are passing as parameters.

Example:

Cpp

Output: 

Template Argument Deduction

C++ uses template argument deduction, allowing the compiler to deduce T from the arguments passed to the template function. This helps avoid unnecessary type declarations, resulting in less verbose and more readable code. It does this automatically during compile time, based on the types of the parameters.

1. Function Template Argument Deduction

Argument deduction refers only to function templates. Function templates allow you to define a general function that can operate on multiple data types, with the template's types being deduced automatically based on the arguments you provide. This not only makes the syntax clearer and more adaptable, but also allows you to avoid mentioning the types explicitly, except when deduction cannot determine the type or more than one type satisfies the requirement.

Example: 

Cpp

Output: 

1. Function Template Argument Deduction

In the above code, the type T would be inferred by the compiler from what you pass to printTwice(). You do not need to write printTwice(100), the compiler deduces it.

2. Class Template Argument Deduction (CTAD)

C++17 introduced Class Template Argument Deduction (CTAD), allowing for the instantiation of class templates without explicit specification of the template type. The type is inferred from the constructor args, just as with function templates.

Example: 

Cpp

Output: 

2. Class Template Argument Deduction (CTAD)

The above code, instead of writing Wrapper w(123); C++17 lets us write Wrapper w(123); and deduces the type T as int from the constructor argument.

Role of Default Template Arguments in C++

Defaults in templates help provide them in a much simpler and repetitive way without duplicating the code. Let's say that the user can ignore a template argument, and the compiler will simply provide the default.

1. What are Default Template Arguments

Template arguments are placeholders for types or values that can be provided when the template is instantiated. This way, you can create a catch-all template that accepts many different data types or values as an argument and just set a default if none is provided.

Syntax:

template <typename T = int>  // Default argument is 'int'
void func(T value) {
std::cout << value << std::endl;
}

Here, T is a template parameter; In case no type is provided, the =int declares the default to int. 

2. Why Use Default Template Arguments?

Default template arguments offer great flexibility and convenience. This lets you define one template definition that works for multiple data types, without having to specify a type every time for the end user. This helps to limit duplicate template overloads or specialisations.

Example: 

Cpp

Output: 

2. Why Use Default Template Arguments

This is a templated Printer class with a general print method and specialisation for const char* to treat C-style strings differently. In main(), p1 prints an int using the more general version, and p2 prints a string. 

Advantages of Templates in C++

  1. Code Reusability - Write once, use for any type.
  2. Type Safety - Type errors are caught at compile time.
  3. Performance - Compile-time resolution avoids runtime overhead.
  4. Generic Programming - Enables flexible and powerful abstractions.
  5. Standard Template Library (STL) - Offers a rich set of reusable components.

Disadvantages of Templates in C++

  1. Code Bloat - Each instantiation generates separate code.
  2. Complex Error Messages - Template errors are hard to debug.
  3. Increased Compilation Time - Templates slow down compilation.
  4. Poor Tooling Support - Some IDEs struggle with template analysis.
  5. Steeper Learning Curve - Understanding the templates requires deep C++ knowledge.

Conclusion

In C++, templates are a powerful tool for writing generic and reusable code. They enable type independence, reduce code duplication, and form the foundation of the Standard Template Library (STL). They support functions, classes, multiple parameters, and default values.

Due to the compile-time instantiation, templates enhance type safety and reduce code duplication. Templates are very essential for template programming; The features such as specialisation, non-type parameters, and argument deduction help in building scalable and typesafe applications.

Templates in C++ - FAQs

Q1. What is a template in C++?

A template is used to write generic code that works with any datatype.

Q2. What are the types of templates in C++?

Two types of templates in C++: Function templates and class templates.

Q3. Can templates have multiple parameters?

Yes, there can be multiple types or non-type parameters.

Q4. What is template specialization?

Template specialization in C++ means customizing a template for a specific data type.

Q5. What is the difference between templates and function overloading?

Templates reuse generic code and overload defines separate functions.

About the Author

Technical Research Analyst - Full Stack Development

Kislay is a Technical Research Analyst and Full Stack Developer with expertise in crafting Mobile applications from inception to deployment. Proficient in Android development, IOS development, HTML, CSS, JavaScript, React, Angular, MySQL, and MongoDB, he’s committed to enhancing user experiences through intuitive websites and advanced mobile applications.

Full Stack Developer Course Banner