Giao diện
🔧 Function Templates — Generic Functions
Function templates cho phép viết một function hoạt động với nhiều types khác nhau.
Cú pháp cơ bản
cpp
template<typename T>
T add(T a, T b) {
return a + b;
}
// Hoặc dùng 'class' thay cho 'typename' (tương đương)
template<class T>
T multiply(T a, T b) {
return a * b;
}Sử dụng
cpp
#include <iostream>
#include <string>
template<typename T>
T add(T a, T b) {
return a + b;
}
int main() {
// Explicit type specification
int x = add<int>(5, 3); // 8
double y = add<double>(2.5, 3.7); // 6.2
// Type deduction (compiler tự suy ra)
int a = add(5, 3); // Deduced as add<int>
double b = add(2.5, 3.7); // Deduced as add<double>
std::string s = add(std::string("Hello "), std::string("World"));
// "Hello World"
return 0;
}Template Instantiation
┌─────────────────────────────────────────────────────────────────┐
│ TEMPLATE INSTANTIATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Source code: template<typename T> T add(T a, T b); │
│ │ │
│ ▼ │
│ Compiler sees: add(5, 3) add(2.5, 3.7) add(s1, s2) │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ Generates: add<int> add<double> add<string> │
│ │
│ Binary contains 3 separate functions! │
│ │
└─────────────────────────────────────────────────────────────────┘Đây là compile-time code generation — no runtime overhead!
Multiple Template Parameters
cpp
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
// C++14 simplified (auto return type deduction)
template<typename T, typename U>
auto multiply(T a, U b) {
return a * b;
}
int main() {
auto result = add(5, 2.5); // int + double = double
auto result2 = multiply(3, 4.0); // int * double = double
return 0;
}Non-type Template Parameters
cpp
// N là compile-time constant
template<typename T, int N>
T arraySum(T (&arr)[N]) {
T sum = T();
for (int i = 0; i < N; ++i) {
sum += arr[i];
}
return sum;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int sum = arraySum(arr); // N deduced as 5
std::cout << sum << std::endl; // 15
return 0;
}Non-type Parameter Examples
cpp
template<int N>
struct FixedBuffer {
char data[N];
};
template<typename T, std::size_t Size>
class Array {
T data_[Size];
public:
constexpr std::size_t size() const { return Size; }
T& operator[](std::size_t i) { return data_[i]; }
};
Array<int, 10> arr; // Fixed-size array of 10 intsDefault Template Arguments
cpp
template<typename T = int, typename U = double>
auto compute(T a, U b) {
return a + b;
}
int main() {
auto r1 = compute(5, 3.0); // T=int, U=double
auto r2 = compute<float>(5, 3.0); // T=float, U=double
auto r3 = compute<float, float>(5, 3); // T=float, U=float
return 0;
}Template Overloading
cpp
#include <iostream>
#include <cstring>
// Generic version
template<typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
// Overload for C-strings (char*)
const char* maximum(const char* a, const char* b) {
return (std::strcmp(a, b) > 0) ? a : b;
}
int main() {
std::cout << maximum(10, 20) << std::endl; // 20
std::cout << maximum(3.14, 2.71) << std::endl; // 3.14
std::cout << maximum("apple", "banana") << std::endl; // banana
return 0;
}SFINAE (Substitution Failure Is Not An Error)
cpp
#include <type_traits>
// Enable chỉ cho integral types
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
increment(T value) {
return value + 1;
}
// Enable chỉ cho floating point
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
increment(T value) {
return value + 0.1;
}
int main() {
auto a = increment(5); // Calls integral version: 6
auto b = increment(5.0); // Calls floating point version: 5.1
// increment("hello"); // ❌ Error: no matching function
return 0;
}📌 SFINAE
Nếu template substitution thất bại, compiler không báo lỗi mà thử overload khác. Đây là cách "chọn lọc" templates trước C++20.
Variadic Templates (C++11)
cpp
#include <iostream>
// Base case
void print() {
std::cout << std::endl;
}
// Recursive case
template<typename T, typename... Args>
void print(T first, Args... rest) {
std::cout << first << " ";
print(rest...); // Recursively expand
}
int main() {
print(1, 2.5, "hello", 'a');
// Output: 1 2.5 hello a
return 0;
}Fold Expressions (C++17)
cpp
// C++17: Much cleaner!
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // Unary right fold
}
template<typename... Args>
void printAll(Args... args) {
((std::cout << args << " "), ...); // Comma fold
std::cout << std::endl;
}
int main() {
std::cout << sum(1, 2, 3, 4, 5) << std::endl; // 15
printAll(1, 2.5, "hello"); // 1 2.5 hello
return 0;
}Common Patterns
Swap
cpp
template<typename T>
void mySwap(T& a, T& b) {
T temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}Max/Min
cpp
template<typename T>
const T& myMax(const T& a, const T& b) {
return (a > b) ? a : b;
}Print Container
cpp
template<typename Container>
void printContainer(const Container& c) {
for (const auto& elem : c) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
// Works with vector, list, array, deque, etc.
std::vector<int> v = {1, 2, 3};
printContainer(v); // 1 2 3📚 Tổng kết
| Feature | Syntax |
|---|---|
| Basic template | template<typename T> |
| Multiple params | template<typename T, typename U> |
| Non-type param | template<typename T, int N> |
| Default | template<typename T = int> |
| Variadic | template<typename... Args> |
| Fold expression | (args + ...) (C++17) |
➡️ Tiếp theo
Tiếp theo: Class Templates — Generic classes.