Templates:
In C++, a template is a powerful feature that allows you to create generic functions or classes. It provides a way to define a blueprint or pattern for generating specific functions or classes based on different types. Templates serve as a mechanism for code reusability, allowing you to write generic code that can work with multiple data types without duplicating code for each type.
Templates can be used to create two main types of entities: function templates and class templates.
Function Templates:
A function template allows you to define a generic function that can work with multiple types. It provides a blueprint for generating specific functions based on the template parameters.
Syntax:
template <typename T>
return_type function_name(T parameter)
{
// Function body
}
Example:
template <typename T>
T add(T a, T b)
{
return a + b;
}
In this example, the `add` function template takes two parameters of type `T` and returns their sum. The `T` represents a placeholder for any type that will be determined when the function is instantiated.
Usage:
int result1 = add<int>(5, 10); // result1 = 15 (int)
double result2 = add<double>(3.14, 2.71); // result2 = 5.85 (double)
The function template `add` is used to perform addition for both `int` and `double` types, providing type-generic behavior without code duplication.
Class Templates:
A class template allows you to define a generic class that can be instantiated with different types. It provides a blueprint for generating specific classes based on the template parameters.
Syntax:
template <typename T>
class ClassName
{
// Class body
};
Example:
template <typename T>
class Stack
{
private:
T elements[100];
int top;
public:
Stack()
{
top = 0;
}
void push(T element)
{
elements[top++] = element;
}
T pop()
{
return elements[--top];
}
bool isEmpty()
{
return top == 0;
}
};
In this example, the `Stack` class template is defined with a single template parameter `T`, representing the type of elements that the stack can hold.
Usage:
Stack<int> intStack;
intStack.push(10);
intStack.push(20);
intStack.push(30);
while (!intStack.isEmpty())
{
int value = intStack.pop();
cout << value << " "; // Output: 30 20 10
}
cout << endl;
Stack<string> stringStack;
stringStack.push("Hello");
stringStack.push("World");
while (!stringStack.isEmpty())
{
string value = stringStack.pop();
cout << value << " "; // Output: World Hello
}
cout << endl;
Template Specialization:
Template specialization allows you to provide specific implementations for certain template types, overriding the generic template for those types.
Syntax:
template <>
return_type function_name<specific_type>(specific_type parameter)
{
// Specialized implementation
}
Example:
template <>
double add<double>(double a, double b)
{
return a + b + 1.0; // Specialized implementation for doubles
}
In this example, the `add` function template is specialized for `double` types. It adds an additional value of `1.0` to the sum.
Usage:
double result3 = add<double>(3.14, 2.71); // result3 = 6.85 (double
The specialized version of the `add` function template is used when the arguments are of type `double`, providing a specific behavior for that data type.
Template Arguments:
Multiple Template Arguments:
Templates can accept multiple template arguments, allowing for the specification of more complex types or multiple arguments.
Syntax:
template <typename T, typename U>
return_type function_name(T arg1, U arg2)
{
// Function body
}
Example:
template <typename T, typename U>
void printPair(T first, U second)
{
cout << "Pair: " << first << ", " << second << endl;
}
In this example, the `printPair` function template takes two template arguments (`T` and `U`) representing the types of the first and second elements of a pair. The function simply prints the pair elements.
Usage:
printPair<int, string>(10, "Hello"); // Output: Pair: 10, Hello
printPair<double, char>(3.14, 'A'); // Output: Pair: 3.14, A
The function template `printPair` is used to print pairs with different types for the first and second elements.
Default Template Arguments:
Default template arguments allow you to provide default values for template parameters. These default values are used when the template arguments are not explicitly specified.
Syntax:
template <typename T = default_type>
return_type function_name(T parameter)
{
// Function body
}
Example:
template <typename T = int, int size = 10>
class Array
{
private:
T elements[size];
public:
void set(int index, const T& value)
{
elements[index] = value;
}
T get(int index)
{
return elements[index];
}
};
int main()
{
Array<> intArray;
intArray.set(0, 10);
intArray.set(1, 20);
cout << "Element at index 0: " << intArray.get(0) << endl;
cout << "Element at index 1: " << intArray.get(1) << endl;
Array<double, 5> doubleArray;
doubleArray.set(0, 3.14);
doubleArray.set(1, 2.71);
cout << "Element at index 0: " << doubleArray.get(0) << endl;
cout << "Element at index 1: " << doubleArray.get(1) << endl;
return 0;
}
In this example, we have a class template `Array` that represents a generic array. It has two template parameters: `T` for the element type and `size` for the size of the array. Both template parameters have default values: `int` for `T` and `10` for `size`.
Output:
Element at index 0: 10
Element at index 1: 20
Element at index 0: 3.14
Element at index 1: 2.71
Member Function Templates:
Member function templates allow you to define generic member functions within a class. They provide a way to write generic functions that operate on different types while being part of a class.
Syntax:
class ClassName
{
public:
template <typename T>
return_type function_name(T parameter)
{
// Function body
}
};
Example:
class MathOperations
{
public:
template <typename T>
T multiply(T a, T b)
{
return a * b;
}
};
In this example, the `MathOperations` class has a member function template `multiply`, which takes two parameters of type `T` and returns their product.
Usage:
MathOperations math;
int result1 = math.multiply<int>(5, 10); // result1 = 50 (int)
double result2 = math.multiply<double>(3.14, 2.71); // result2 = 8.5094 (double)
we can also declare a member template function outside the class:
Syntax:
class ClassName
{
public:
template <typename T>
return_type function_name(T parameter);
};
template <typename T>
return_type ClassName::function_name(T parameter)
{
// Function body
}
Example:
class MathOperations
{
public:
template <typename T>
T multiply(T a, T b);
};
template <typename T>
T MathOperations::multiply(T a, T b)
{
return a * b;
}
In this example, the `multiply` member template function is declared inside the `MathOperations` class but defined outside the class definition.
Usage:
MathOperations math;
int result = math.multiply<int>(5, 10); // result = 50 (int)
Overloading Template Functions:
Template functions can be overloaded just like regular functions, allowing you to provide different implementations for different argument types.
Syntax:
template <typename T>
return_type function_name(T parameter)
{
// Function body
}
template <typename U>
return_type function_name(U parameter)
{
// Function body
}
Example:
template <typename T>
T add(T a, T b)
{
return a + b;
}
template <typename U>
U add(U a, U b, U c)
{
return a + b + c;
}
In this example, we have two overloaded template functions `add`. One takes two parameters, and the other takes three parameters. Both functions perform addition, but they can handle different numbers of arguments.
Usage:
int result1 = add<int>(5, 10); // result1 = 15 (int)
double result2 = add<double>(3.14, 2.71); // result2 = 5.85 (double)
int result3 = add<int>(1, 2, 3); // result3 = 6 (int)
double result4 = add<double>(1.5, 2.5, 3.5); // result4 = 7.5 (double)