Skip to content

Template Basics

🎯 Mục tiêu

🎯 Sau bài thực hành này, bạn sẽ:

  • Viết function templates generic cho nhiều kiểu dữ liệu
  • Tạo class templates có thể tái sử dụng
  • Áp dụng template specialization cho trường hợp đặc biệt
  • Sử dụng type traits để kiểm tra kiểu tại compile-time

Mô tả bài tập

Templates cho phép viết code generic — một lần viết, nhiều kiểu dùng. Đây là nền tảng của STL.

Yêu cầu

Bài 1: Function Templates

Viết maxOfprintArray template.

cpp
template <typename T>
T maxOf(T a, T b) { /* TODO: trả về giá trị lớn hơn */ }

template <typename T, size_t N>
void printArray(const T (&arr)[N]) { /* TODO: in mảng, phân tách ", " */ }

int main() {
    std::cout << maxOf(3, 7) << std::endl;        // 7
    std::cout << maxOf(3.14, 2.71) << std::endl;  // 3.14
    int nums[] = {1, 2, 3, 4, 5};
    printArray(nums);  // 1, 2, 3, 4, 5
}

Bài 2: Class Template — Stack

cpp
template <typename T>
class Stack {
    std::vector<T> data;
public:
    void push(const T& value);   // thêm phần tử
    T pop();                      // xóa và trả về đỉnh, throw nếu rỗng
    const T& top() const;         // xem đỉnh
    bool empty() const;
    size_t size() const;
};

Bài 3: Template Specialization & Type Traits

cpp
template <typename T>
std::string format(const T& value) { return std::to_string(value); }

// TODO: Specialization cho std::string (trả về trực tiếp)
// TODO: Specialization cho bool (trả về "true"/"false")

template <typename T>
T safeAdd(T a, T b) {
    static_assert(std::is_arithmetic_v<T>, "safeAdd requires numeric types");
    return a + b;
}

Gợi ý

Gợi ý Bài 1

maxOf: return (a > b) ? a : b;. printArray: template nhận size N, dùng vòng lặp đến N.

Gợi ý Bài 2

pop(): kiểm tra data.empty(), lưu data.back(), gọi data.pop_back(), return.

Lời giải tham khảo

Xem lời giải
cpp
template <typename T>
T maxOf(T a, T b) { return (a > b) ? a : b; }

template <typename T, size_t N>
void printArray(const T (&arr)[N]) {
    for (size_t i = 0; i < N; ++i) {
        if (i > 0) std::cout << ", ";
        std::cout << arr[i];
    }
    std::cout << std::endl;
}

template <typename T>
void Stack<T>::push(const T& value) { data.push_back(value); }
template <typename T>
T Stack<T>::pop() {
    if (data.empty()) throw std::runtime_error("Stack is empty");
    T val = data.back(); data.pop_back(); return val;
}
template <typename T>
const T& Stack<T>::top() const {
    if (data.empty()) throw std::runtime_error("Stack is empty");
    return data.back();
}

template <> std::string format<std::string>(const std::string& v) { return v; }
template <> std::string format<bool>(const bool& v) { return v ? "true" : "false"; }