Templates and Typing in C++: From Generics to Concepts

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Generics and Typing in C++: Why It's Not "Just Templates"?



When a developer transitions from Python or Java to C++, they are often intimidated by the word "template". Associations arise with endless angle brackets, incomprehensible compilation errors, and the magic of std::vector<int>. In reality, generics in C++ (or generic programming) is a powerful tool that allows you to write code once and use it with any data type. And yes, it is not the same as generics in Java or C#.



In this article, we will break down how typing in C++ works through templates, how class templates differ from function templates, and why concepts were added in C++20. There will be many examples — from simple ones to those that are truly useful in production. Let's go!



What are Generics (Templates) in C++?



To put it simply: templates in C++ are a way to write code that works with any data type without losing performance. Unlike Python's dynamic typing, where the type is checked at runtime, C++ generates a separate version of a function or class for each used type at compile time. This is called static typing with parameterization.



Syntactically, a template is declared using the keyword template and angle brackets with parameters:



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


Here, typename T is the template parameter. You can use class instead of typename — there is no difference. When you write max(3, 7), the compiler automatically substitutes int for T and creates the function int max(int, int). If you write max(3.14, 2.71), you get the version for double. Simple and efficient.



Function Templates: The First Step to Generics



Let's start small — function templates in C++. This is an ideal way to avoid code duplication when the logic is the same but the types are different.



Example: a function that prints an element to the console (useful for debugging):



#include <iostream>#include <string>

template <typename T>void print(const T& value) { std::cout << value << std::endl;}

int main() { print(42); // int print(3.1415); // double print("Hello"); // const char* print(std::string("Generics!")); // std::string return 0;}


Note: we use const T& — this is typing in C++ with passing by const reference to avoid copying large objects. For built-in types (int, double) this is not critical, but it's a good habit.



What if you need to pass two arguments of different types? Easy:



template <typename T1, typename T2>auto add(T1 a, T2 b) -> decltype(a + b) {    return a + b;}

// In C++14 and later you can simply:template <typename T1, typename T2>auto add(T1 a, T2 b) { return a + b;}


Here, auto deduces the return type automatically. This is generics in action — one code, an infinite number of type combinations.



Class Templates: Building Universal Structures



Now let's move on to class templates in C++. This is the foundation of the Standard Library (STL): std::vector<T>, std::map<Key, Value>, std::optional<T> — all are implemented using templates.



Let's write a simple but illustrative example — a template class "Pair" (analogous to std::pair):



template <typename First, typename Second>class Pair {private:    First first_;    Second second_;public:                

Blogs

Book Recommendations