## DEV Community

Coral Kashri

Posted on • Originally published at cppsenioreas.wordpress.com on

# C++ Basic templates usage – Part 1

This is the second article in the series of meta programming tutorials. Here we'll see a very basic usage of templates in C++. Due to the amount of content that fits into the basic usage of templates, I separated this article into 2 parts. In this part I'll talk about the usage in functions & classes, and about how the compiler handle them.

Next post on series: Basic templates usage – Part 2

# Generic Functions

Assume you have the following function:

``````int sum(int num1, int num2) { return num1 + num2;}
``````

Now you might want to apply the exact same functionality for float & double:

``````float sum(float num1, float num2) {
return num1 + num2;
}

double sum(double num1, double num2) {
return num1 + num2;
}
``````

The code just got 3 times expanded. This is where the templates come to our help. Templates give us the option to accept any type, and to apply the same algorithms for all of them (in future posts I’ll show how to make the compiler choose between different algorithms for different types in the same function, but for now- same algorithm different types). Let’s have a look on templates in action:

``````template <typename T>
T sum(T num1, T num2) {
return num1 + num2;
}

int main() {
int n1, n2;
float n3, n4;
double n5, n6;
std::string a, b;

n1 = 1; n2 = 2;
n3 = 3.5f; n4 = 4.3f;
n5 = 5.2; n6 = 6.1;
a = "Hello "; b = "World";
std::cout << sum<int>(n1, n2) << std::endl; // Prints 3
std::cout << sum<float>(n3, n4) << std::endl; // Prints 7.8
std::cout << sum<double>(n5, n6) << std::endl; // Prints 11.3
std::cout << sum<std::string>(a, b) << std::endl; // Prints "Hello World". Note: From the function's name it's clearly that this isn't the expected usage, but the compiler doesn't know it. We'll see in future posts how to handle such cases.

return EXIT_SUCCESS;
}
``````

## How Does It Work?

For every new call type to the template function, the compiler generates a new function specialization with the new types (since the types are known at compile time). For example, in our case the compiled code will look something like this:

``````template <typename T>
T sum(T num1, T num2) {
return num1 + num2;
}

// Integer specialization
template<>
int sum<int>(int num1, int num2) {
return num1 + num2;
}

// Float specialization
template<>
float sum<float>(float num1, float num2) {
return num1 + num2;
}

// Double specialization
template<>
double sum<double>(double num1, double num2) {
return num1 + num2;
}

// std::string specialization
template<>
std::string sum<std::string>(std::string num1, std::string num2) {
return num1 + num2;
}

// ... main ...
``````

## Function Specializations Deduction

In simple cases, when the compiler is able to automatically deduce the function template types just from the passed parameters, we don’t have to explicitly specify the types. For example, we could call sum this way:

``````int main() {
/* ... Variable Declarations ... */

std::cout << sum(n1, n2) << std::endl; // Prints 3
std::cout << sum(n3, n4) << std::endl; // Prints 7.8
std::cout << sum(n5, n6) << std::endl; // Prints 11.3
std::cout << sum(a, b) << std::endl; // Prints "Hello World".

return EXIT_SUCCESS;}
``````

# Generic Classes

The basic templates usage in classes is similar to the functions one. Assume you have a class that handles an integer

``````class my_class {
public:
explicit my_class(int val) : m_val(val) {}
void print_val() const { std::cout << m_val << std::endl; }
[[nodiscard]] int get() const { return m_val; }
void set(int val) { m_val = val; }

int m_val;
};
``````

Now, to make this function also handle a float, double, std::string, and char, you’ll have to create 4 more separate classes, with 4 different names.

Why can’t you just create 4 different classes with the same name, like we did with the functions?

unlike functions, there is no such a thing “class overloading”, for a simple reason: At compile time, the compiler don’t know which class you refer to, and which class you want to create. The error you’ll get for trying define the same class name twice or more: “`Redefinition of 'class_name'`”.

To archive a single class that handle a single variable of different type every time you have several options:

1. Use templates.
2. Use std::variant (which is also implemented using template).

I'll show here the solution using templates, because std::variant is not in the scope of this series (I might talk about it in a future independent post).

``````template <typename T>
class my_class {
public:
explicit my_class(T val) : m_val(val) {}
void print_val() const { std::cout << m_val << std::endl; }
[[nodiscard]] T get() const { return m_val; }
void set(T val) { m_val = val; }

T m_val;
};

int main() {
my_class<int> mc_i(5);
my_class<double> mc_d(3.6);

return EXIT_SUCCESS;
}
``````

## Class Specializations Behind The Scenes

Same as in the functions, for every new type usage of this class, the compiler will generate a complete class specialization. In our case:

``````template <typename T>
class my_class {
public:
explicit my_class(T val) : m_val(val) {}
void print_val() const { std::cout << m_val << std::endl; }
[[nodiscard]] T get() const { return m_val; }
void set(T val) { m_val = val; }

T m_val;
};

// Integer specialization
template<>
class my_class<int> {
public:
explicit my_class(int val) : m_val(val) {}
void print_val() const { std::cout << m\_val << std::endl; }
[[nodiscard]] int get() const { return m_val; }
void set(int val) { m_val = val; }

int m_val;
};

// Double specialization
template<>
class my_class<double> {
public:
explicit my_class(double val) : m_val(val) {}
void print_val() const { std::cout << m_val << std::endl; }
[[nodiscard]] double get() const { return m_val; }
void set(double val) { m_val = val; }

double m_val;
};
``````

This way the compiler can make the decision which my_class specialization you refer to in your code.

## Class Specializations Deduction

Since the class’s CTOR signature is different for every specialization, you don’t have to explicitly mention the class type:

``````int main() {
my_class mc_i(5); // Integer specialization
my_class mc_l(5l); // Long specialization
my_class mc_d(5.0); // Double specialization
my_class mc_f(5.f); // Float specialization

return EXIT_SUCCESS;
}
``````

However, to use a CTOR that doesn’t have a unique signature for an specialization, you’ll still have to explicitly mention the type:

``````// my_class::my_class() {}

int main() {
// my_class mc_i; // Deduction failure: "No viable constructor or deduction guide for deduction of template arguments of 'my_class'"
my_class<int> mc_i; // Integer specialization

return EXIT_SUCCESS;}
``````

# Conclusion

This is all for the first part of basic templates usage. You are more than welcome to share your thoughts about templates and the instantiations. Personally, it took me long time to agree with the way the compiler copy the class for every different type of usage, back in the days it just seemed to me like a huge waste of code memory. Today I think it’s better than slow down performances in order to deduce the types at run time.

This post originally published on my personal blog: C++ Senioreas.

DEV Community

## The AI Brief

### AI generated git commit messages

Minimize the struggle of remembering what you just coded. AI-generated commits make it easier to manage projects and keep track of changes. The Nutlope/aicommits project demonstrates how AI can improve commit messages.

### I open sourced an AI that creates any UI in seconds

Make AI-generated user interfaces a breeze. This open-source project harnesses the power of generative AI technologies like chatGPT to create versatile, quick, and intuitive UI components.

### Use AI to commit like a PRO in 1 second

Upgrade your commit message game with AI. Boost your productivity by using ChatGPT to generate commit messages and avoid context switching. OpenCommit is an open-source library that helps you achieve this easily.

### Build your own ChatGPT starter kit

Train AI models on custom data for improved domain-specific knowledge. Combine the power of WebView technologies and this starter kit to train your ChatGPT model on specific websites, allowing for better-optimized outcomes.