Templates in C++ provide a way to write flexible, reusable code for multiple data types without having to rewrite similar logic for each type. This capability is particularly useful for:
- Avoiding code duplication.
- Writing type-independent code.
- Enhancing reusability.
§1 Function Templates #
Function templates allow you to write a single function that can work with different data types. Instead of writing separate functions for int, double, float, etc., you can create one template function that handles them all.
Syntax:
template <typename T>
T functionName(T parameter1, T parameter2) {
// Function logic using parameters of type T
}
template <typename T>tells the compiler thatTis a placeholder for a type.Tcan be any data type, such asint,double,char, etc.functionName()is the name of the function, andTwill be replaced with the actual type when the function is called.
Example: A function to find the maximum of two values:
template <typename T>
T getMax(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << "Max of 3 and 7 is " << getMax(3, 7) << std::endl;
std::cout << "Max of 3.5 and 2.1 is " << getMax(3.5, 2.1) << std::endl;
std::cout << "Max of 'a' and 'z' is " << getMax('a', 'z') << std::endl;
}
In this example:
- The function
getMax()can work with any comparable type with an implemented<operator>, such asint,double, andchartypes. - The compiler automatically generates the appropriate version of
getMax()when called.
§2 Class Templates #
Class templates allow you to create a template for a class that can handle different data types. Instead of writing separate classes for each data type, you can create one class template that can store and manipulate any type.
Syntax:
template <typename T>
class ClassName {
public:
T data;
ClassName(T val) : data(val) {}
void display() {
std::cout << "Data: " << data << std::endl;
}
};
Example: A simple class template to store and display a value of any type.
template <typename T>
class Box {
private:
T value;
public:
Box(T v) : value(v) {}
void show() {
std::cout << "Box value: " << value << std::endl;
}
};
int main() {
Box<int> intBox(123);
Box<double> doubleBox(45.67);
Box<std::string> stringBox("Hello, World!");
intBox.show();
doubleBox.show();
stringBox.show();
}
$ ./example
Box value: 123
Box value: 45.67
Box value: Hello, World!
In this example:
Box<int> intBox(123);stores an integer.Box<double> doubleBox(45.67);stores a double.Box<string> stringBox("Hello, World!");stores a string.
The Box class can store any data type, thanks to the template parameter T.
§3 Multiple Template Parameters #
Templates can be defined to accept multiple different types within a single class or function. This allows a function or class to accept and work with more than one type.
When defining a class template that takes multiple types, you can specify each type as a separate template parameter in the template declaration. For example:
// define multiple different template parameters
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(T1 a, T2 b) : first(a), second(b) {}
T1 getFirst() const {
return first;
}
T2 getSecond() const {
return second;
}
void display() const {
std::cout << "First: " << first << ", Second: " << second << std::endl;
}
};
int main() {
// define each templated type
Pair<int, std::string> intStringPair(42, "Answer");
Pair<double, char> doubleCharPair(3.14, 'A');
intStringPair.display(); // Output: First: 42, Second: Answer
doubleCharPair.display(); // Output: First: 3.14, Second: A
}
Here:
T1andT2represent two different types that ourPairclass can work with.- The class can store two values of potentially different types, one in first (of type
T1) and the other in second (of typeT2).
§4 Template Specialization #
Sometimes, a generic template does not work well for all types. Template specialization allows you to define a specific implementation of a template for a particular type.
Example: Specializing the Box class to work with the string data type:
template <typename T>
class Box {
public:
T value;
Box(T v) : value(v) {}
void show() {
std::cout << "Box value: " << value << std::endl;
}
};
// Template specialization for strings
// we redefine the `Box` class with a specific template implementation for `string` types
template <>
class Box<std::string> {
public:
string value;
Box(string v) : value(v) {}
void show() {
std::cout << "Specialized Box for string: '" << value << "'" << std::endl;
}
};
int main() {
Box<int> intBox(123);
Box<std::string> stringBox("example");
intBox.show(); // prints: Box value: 123
stringBox.show(); // prints: Specialized Box for string: 'example'
}
In this example:
- The
Boxtemplate has been specialized for thestringtype. - When a
Box<string>is instantiated, the specialized definition is used, which uses a different output message.
§5 Advantages and Use Cases #
Templates are commonly used for:
- Container classes, like those in the Standard Template Library:
vector,list,map, etc. - Algorithm implementations, such as
sortandsearch. - Generic utilities, like
swap,max, andminfunctions.
Advantages:
- Code reusability: Templates reduce redundancy and prevent you from writing multiple versions of the same code for different types.
- Ease of maintenance: One template can cover a wide range of data types.
§6 Additional Resources: #
- https://www.geeksforgeeks.org/cpp/templates-cpp/
- https://en.cppreference.com/w/cpp/language/function_template.html
- https://learn.microsoft.com/en-us/cpp/cpp/templates-cpp?view=msvc-170
§7 Questions #
- Provide a short code sample to create a template method/class that can work with two different template types, such as a
stringandintor adoubleandfloat.
- Describe a class template and its benefits.
- Describe a situation where a class template would be useful.
- Why might you need to use template specialization?
- What is the syntax to declare a specialized template class to define special behavior for handling a
float?