模板programming

LearningC++模板 using, includingfunction模板, class模板, 模板特化 - core concepts

返回tutoriallist

1. 模板overview

1.1 what is 模板

模板 is C++inimplementation泛型programming coremechanism, 它允许我们writing and class型无关 code. through模板, 我们可以creation适用于不同dataclass型 function and class, 而不需要 for 每种class型重复writing相同 code.

模板 主要优势including:

  • code复用: writing一次code, 适用于 many 种dataclass型.
  • class型security: in 编译时forclass型check, 避免run时error.
  • flexible性: 可以processing不同class型 parameter and return value.
  • efficiency: 模板 in 编译时instance化, 不会引入run时开销.

1.2 模板 class型

C++in has 两种主要class型 模板:

  • function模板 (Function Templates) : 用于creation可以processing不同class型parameter function.
  • class模板 (Class Templates) : 用于creation可以processing不同class型成员 class.

2. function模板

2.1 function模板 定义

function模板 定义usingtemplate关键字, after 跟模板parameterlist, 然 after is function定义.

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

//  or 者using class 关键字 (效果相同) 
template <class T>
T minimum(T a, T b) {
    return (a < b) ? a : b;
}

2.2 function模板 using

usingfunction模板时, 编译器会根据传入 parameterclass型自动推断模板parameterclass型, or 者我们可以显式指定模板parameterclass型.

#include <iostream>

using namespace std;

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

template <class T>
T minimum(T a, T b) {
    return (a < b) ? a : b;
}

int main() {
    // 自动class型推断
    int a = 10, b = 20;
    cout << "最 big 值: " << maximum(a, b) << endl;
    cout << "最 small 值: " << minimum(a, b) << endl;
    
    double c = 3.14, d = 2.71;
    cout << "最 big 值: " << maximum(c, d) << endl;
    cout << "最 small 值: " << minimum(c, d) << endl;
    
    string e = "apple", f = "banana";
    cout << "最 big 值: " << maximum(e, f) << endl;
    cout << "最 small 值: " << minimum(e, f) << endl;
    
    // 显式指定模板parameter
    cout << "最 big 值: " << maximum<int>(100, 200) << endl;
    cout << "最 small 值: " << minimum<double>(1.5, 2.5) << endl;
    
    return 0;
}

2.3 function模板 重载

function模板可以被重载, 我们可以 for specificclass型providing专门 模板重载version.

#include <iostream>
#include <cstring>

using namespace std;

template <typename T>
T maximum(T a, T b) {
    cout << "usingcommon模板" << endl;
    return (a > b) ? a : b;
}

//  for  const char* class型providing重载
template <>
const char* maximum(const char* a, const char* b) {
    cout << "using const char* 特化模板" << endl;
    return (strcmp(a, b) > 0) ? a : b;
}

// 普通function重载 (priority high 于模板) 
double maximum(double a, double b) {
    cout << "using普通function" << endl;
    return (a > b) ? a : b;
}

int main() {
    int a = 10, b = 20;
    cout << "最 big 值: " << maximum(a, b) << endl; // usingcommon模板
    
    double c = 3.14, d = 2.71;
    cout << "最 big 值: " << maximum(c, d) << endl; // using普通function
    
    const char* e = "apple"; 
    const char* f = "banana";
    cout << "最 big 值: " << maximum(e, f) << endl; // using特化模板
    
    return 0;
}

2.4 many parameterfunction模板

function模板可以 has many 个模板parameter, 用于processing不同class型 parameter.

#include <iostream>

using namespace std;

//  many parameterfunction模板
template <typename T1, typename T2, typename T3>
T3 sum(T1 a, T2 b) {
    return static_cast<T3>(a + b);
}

// 具 has 默认模板parameter function模板 (C++11及以 on ) 
template <typename T1, typename T2 = T1>
T1 add(T1 a, T2 b) {
    return a + b;
}

int main() {
    // using many parameterfunction模板
    int a = 10;
    double b = 3.14;
    cout << " and  (int) : " << sum<int, double, int>(a, b) << endl;
    cout << " and  (double) : " << sum<int, double, double>(a, b) << endl;
    
    // using具 has 默认模板parameter function模板
    cout << "相加结果: " << add(a, b) << endl; // T2 默认 for  int
    cout << "相加结果: " << add<double>(a, b) << endl; // T1 指定 for  double, T2 默认 for  double
    
    return 0;
}

3. class模板

3.1 class模板 定义

class模板 定义usingtemplate关键字, after 跟模板parameterlist, 然 after is class定义.

template <typename T>
class Vector {
private:
    T* data;
    int size;
    int capacity;
public:
    // constructfunction
    Vector(int initialCapacity = 10) {
        capacity = initialCapacity;
        size = 0;
        data = new T[capacity];
    }
    
    // 析构function
    ~Vector() {
        delete[] data;
    }
    
    // 成员function
    void push_back(const T& value) {
        if (size >= capacity) {
            // 扩容
            capacity *= 2;
            T* newData = new T[capacity];
            for (int i = 0; i < size; i++) {
                newData[i] = data[i];
            }
            delete[] data;
            data = newData;
        }
        data[size++] = value;
    }
    
    T& operator[](int index) {
        return data[index];
    }
    
    int getSize() const {
        return size;
    }
};

3.2 class模板 using

usingclass模板时, 需要显式指定模板parameterclass型.

#include <iostream>

using namespace std;

template <typename T>
class Vector {
private:
    T* data;
    int size;
    int capacity;
public:
    // constructfunction
    Vector(int initialCapacity = 10) {
        capacity = initialCapacity;
        size = 0;
        data = new T[capacity];
    }
    
    // 析构function
    ~Vector() {
        delete[] data;
    }
    
    // 成员function
    void push_back(const T& value) {
        if (size >= capacity) {
            // 扩容
            capacity *= 2;
            T* newData = new T[capacity];
            for (int i = 0; i < size; i++) {
                newData[i] = data[i];
            }
            delete[] data;
            data = newData;
        }
        data[size++] = value;
    }
    
    T& operator[](int index) {
        return data[index];
    }
    
    int getSize() const {
        return size;
    }
};

int main() {
    // using int class型  Vector
    Vector<int> intVector;
    intVector.push_back(10);
    intVector.push_back(20);
    intVector.push_back(30);
    
    cout << "intVector 元素: ";
    for (int i = 0; i < intVector.getSize(); i++) {
        cout << intVector[i] << " ";
    }
    cout << endl;
    
    // using double class型  Vector
    Vector<double> doubleVector;
    doubleVector.push_back(1.1);
    doubleVector.push_back(2.2);
    doubleVector.push_back(3.3);
    
    cout << "doubleVector 元素: ";
    for (int i = 0; i < doubleVector.getSize(); i++) {
        cout << doubleVector[i] << " ";
    }
    cout << endl;
    
    // using string class型  Vector
    Vector<string> stringVector;
    stringVector.push_back("Hello");
    stringVector.push_back("World");
    
    cout << "stringVector 元素: ";
    for (int i = 0; i < stringVector.getSize(); i++) {
        cout << stringVector[i] << " ";
    }
    cout << endl;
    
    return 0;
}

3.3 class模板 成员function

class模板 成员function可以 in class in 部定义, 也可以 in class out 部定义. in class out 部定义时, 需要using模板parameterlist.

#include <iostream>

using namespace std;

template <typename T>
class Stack {
private:
    T* data;
    int top;
    int capacity;
public:
    // constructfunction
    Stack(int initialCapacity = 10);
    
    // 析构function
    ~Stack();
    
    // 成员function声明
    void push(const T& value);
    T pop();
    T peek() const;
    bool isEmpty() const;
    int getSize() const;
};

// class模板 成员function in class out 部定义
template <typename T>
Stack<T>::Stack(int initialCapacity) {
    capacity = initialCapacity;
    data = new T[capacity];
    top = -1;
}

template <typename T>
Stack<T>::~Stack() {
    delete[] data;
}

template <typename T>
void Stack<T>::push(const T& value) {
    if (top >= capacity - 1) {
        // 扩容
        capacity *= 2;
        T* newData = new T[capacity];
        for (int i = 0; i <= top; i++) {
            newData[i] = data[i];
        }
        delete[] data;
        data = newData;
    }
    data[++top] = value;
}

template <typename T>
T Stack<T>::pop() {
    if (isEmpty()) {
        throw "Stack is empty";
    }
    return data[top--];
}

template <typename T>
T Stack<T>::peek() const {
    if (isEmpty()) {
        throw "Stack is empty";
    }
    return data[top];
}

template <typename T>
bool Stack<T>::isEmpty() const {
    return top == -1;
}

template <typename T>
int Stack<T>::getSize() const {
    return top + 1;
}

int main() {
    Stack<int> stack;
    stack.push(10);
    stack.push(20);
    stack.push(30);
    
    cout << "栈顶元素: " << stack.peek() << endl;
    cout << "栈 big  small : " << stack.getSize() << endl;
    
    cout << "弹出元素: " << stack.pop() << endl;
    cout << "弹出元素: " << stack.pop() << endl;
    cout << "栈 big  small : " << stack.getSize() << endl;
    
    return 0;
}

3.4 class模板 特化

class模板可以被特化, for specificclass型providing专门 implementation.

#include <iostream>
#include <cstring>

using namespace std;

// commonclass模板
template <typename T>
class Compare {
public:
    bool isEqual(T a, T b) {
        return a == b;
    }
};

// class模板特化 ( for  const char* class型providing专门implementation) 
template <>
class Compare<const char*> {
public:
    bool isEqual(const char* a, const char* b) {
        return strcmp(a, b) == 0;
    }
};

int main() {
    // usingcommonclass模板
    Compare<int> intCompare;
    cout << "10 == 20: " << (intCompare.isEqual(10, 20) ? "相etc." : "不相etc.") << endl;
    cout << "10 == 10: " << (intCompare.isEqual(10, 10) ? "相etc." : "不相etc.") << endl;
    
    // using特化 class模板
    Compare<const char*> stringCompare;
    cout << "\"Hello\" == \"World\": " << (stringCompare.isEqual("Hello", "World") ? "相etc." : "不相etc.") << endl;
    cout << "\"Hello\" == \"Hello\": " << (stringCompare.isEqual("Hello", "Hello") ? "相etc." : "不相etc.") << endl;
    
    return 0;
}

4. 模板 advanced features

4.1 可变parameter模板

可变parameter模板 (Variadic Templates) is C++11引入 features, 允许模板接受任意数量 模板parameter.

#include <iostream>

using namespace std;

// 递归终止function
void print() {
    cout << "\n";
}

// 可变parameter模板function
template <typename T, typename... Args>
void print(T first, Args... rest) {
    cout << first << " ";
    print(rest...); // 递归调用
}

// 计算可变parameter  and 
template <typename T>
T sum(T value) {
    return value;
}

template <typename T, typename... Args>
T sum(T first, Args... rest) {
    return first + sum(rest...);
}

int main() {
    // using可变parameter模板function打印 many 个值
    cout << "打印 many 个值: ";
    print(10, 3.14, "Hello", 'A');
    
    // using可变parameter模板function计算 and 
    cout << " and : " << sum(1, 2, 3, 4, 5) << endl;
    cout << " and : " << sum(1.1, 2.2, 3.3) << endl;
    
    return 0;
}

4.2 模板 模板parameter

模板 模板parameter允许我们将模板serving as另一个模板 parameter.

#include <iostream>
#include <vector>
#include <list>

using namespace std;

// 模板 模板parameter
template <typename T, template <typename> class Container>
class MyContainer {
private:
    Container<T> container;
public:
    void add(const T& value) {
        container.push_back(value);
    }
    
    void display() {
        for (const auto& item : container) {
            cout << item << " ";
        }
        cout << endl;
    }
};

//  for 了兼容标准librarycontainers (它们 has  many 个模板parameter) , 需要调整模板parameter
template <typename T, template <typename...> class Container>
class GenericContainer {
private:
    Container<T> container;
public:
    void add(const T& value) {
        container.push_back(value);
    }
    
    void display() {
        for (const auto& item : container) {
            cout << item << " ";
        }
        cout << endl;
    }
};

int main() {
    // using自定义containers
    /*
    MyContainer<int, vector> myVec;
    myVec.add(10);
    myVec.add(20);
    myVec.add(30);
    cout << "MyContainer with vector: ";
    myVec.display();
    */
    
    // usingcommoncontainers (兼容标准librarycontainers) 
    GenericContainer<int, vector> genericVec;
    genericVec.add(10);
    genericVec.add(20);
    genericVec.add(30);
    cout << "GenericContainer with vector: ";
    genericVec.display();
    
    GenericContainer<string, list> genericList;
    genericList.add("Hello");
    genericList.add("World");
    cout << "GenericContainer with list: ";
    genericList.display();
    
    return 0;
}

4.3 class型别名 and 别名模板

C++11引入了using关键字来creationclass型别名, including别名模板.

#include <iostream>
#include <vector>

using namespace std;

// 传统 class型别名 (using typedef) 
typedef vector<int> IntVector;

// C++11 class型别名 (using using) 
using DoubleVector = vector<double>;

// 别名模板 (C++11及以 on ) 
template <typename T>
using Vec = vector<T>;

// 带 has 模板parameter 别名模板
template <typename T, typename Allocator = std::allocator<T>>
using MyVector = vector<T, Allocator>;

int main() {
    // using传统 class型别名
    IntVector iv;
    iv.push_back(10);
    iv.push_back(20);
    cout << "IntVector size: " << iv.size() << endl;
    
    // using C++11  class型别名
    DoubleVector dv;
    dv.push_back(1.1);
    dv.push_back(2.2);
    cout << "DoubleVector size: " << dv.size() << endl;
    
    // using别名模板
    Vec<int> v1;
    v1.push_back(100);
    v1.push_back(200);
    cout << "Vec<int> size: " << v1.size() << endl;
    
    Vec<string> v2;
    v2.push_back("Hello");
    v2.push_back("World");
    cout << "Vec<string> size: " << v2.size() << endl;
    
    return 0;
}

5. 模板 实践application

5.1 implementationcommon sortalgorithms

#include <iostream>
#include <vector>

using namespace std;

// common 冒泡sort模板function
template <typename T>
void bubbleSort(T arr[], int size) {
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换元素
                T temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

// common 打印array模板function
template <typename T>
void printArray(T arr[], int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    // sort整型array
    int intArr[] = {64, 34, 25, 12, 22, 11, 90};
    int intSize = sizeof(intArr) / sizeof(intArr[0]);
    cout << "sort before : ";
    printArray(intArr, intSize);
    bubbleSort(intArr, intSize);
    cout << "sort after : ";
    printArray(intArr, intSize);
    
    // sort双精度浮点型array
    double doubleArr[] = {64.5, 34.2, 25.7, 12.9, 22.1, 11.5, 90.8};
    int doubleSize = sizeof(doubleArr) / sizeof(doubleArr[0]);
    cout << "\nsort before : ";
    printArray(doubleArr, doubleSize);
    bubbleSort(doubleArr, doubleSize);
    cout << "sort after : ";
    printArray(doubleArr, doubleSize);
    
    // sort字符array
    char charArr[] = {'d', 'b', 'a', 'c', 'f', 'e'};
    int charSize = sizeof(charArr) / sizeof(charArr[0]);
    cout << "\nsort before : ";
    printArray(charArr, charSize);
    bubbleSort(charArr, charSize);
    cout << "sort after : ";
    printArray(charArr, charSize);
    
    return 0;
}

5.2 implementationcommon 智能指针

#include <iostream>

using namespace std;

// common 智能指针模板class
template <typename T>
class SmartPointer {
private:
    T* ptr;
public:
    // constructfunction
    explicit SmartPointer(T* p = nullptr) : ptr(p) {
        cout << "constructfunction调用" << endl;
    }
    
    // 析构function
    ~SmartPointer() {
        cout << "析构function调用" << endl;
        delete ptr;
    }
    
    // 拷贝constructfunction (禁用) 
    SmartPointer(const SmartPointer&) = delete;
    
    // 拷贝赋值运算符 (禁用) 
    SmartPointer& operator=(const SmartPointer&) = delete;
    
    // moveconstructfunction (C++11及以 on ) 
    SmartPointer(SmartPointer&& other) noexcept : ptr(other.ptr) {
        cout << "moveconstructfunction调用" << endl;
        other.ptr = nullptr;
    }
    
    // move赋值运算符 (C++11及以 on ) 
    SmartPointer& operator=(SmartPointer&& other) noexcept {
        cout << "move赋值运算符调用" << endl;
        if (this != &other) {
            delete ptr;
            ptr = other.ptr;
            other.ptr = nullptr;
        }
        return *this;
    }
    
    // 重载解引用运算符
    T& operator*() const {
        return *ptr;
    }
    
    // 重载箭头运算符
    T* operator->() const {
        return ptr;
    }
    
    // check指针 is 否 for 空
    bool isNull() const {
        return ptr == nullptr;
    }
};

class Test {
public:
    Test() {
        cout << "Testconstructfunction调用" << endl;
    }
    
    ~Test() {
        cout << "Test析构function调用" << endl;
    }
    
    void print() {
        cout << "Test::print()调用" << endl;
    }
};

int main() {
    // using智能指针management动态分配 object
    cout << "=== creation智能指针 ===" << endl;
    SmartPointer<Test> sp1(new Test());
    sp1->print();
    (*sp1).print();
    
    // usingmoveconstructfunction
    cout << "\n=== usingmoveconstructfunction ===" << endl;
    SmartPointer<Test> sp2 = move(sp1);
    cout << "sp1 is 否 for 空: " << (sp1.isNull() ? " is " : "否") << endl;
    sp2->print();
    
    // usingmove赋值运算符
    cout << "\n=== usingmove赋值运算符 ===" << endl;
    SmartPointer<Test> sp3;
    sp3 = move(sp2);
    cout << "sp2 is 否 for 空: " << (sp2.isNull() ? " is " : "否") << endl;
    sp3->print();
    
    cout << "\n=== 程序结束 ===" << endl;
    return 0;
}

实践case: implementationcommon 线性搜索algorithms

using模板implementation一个common 线性搜索algorithms, 可以搜索不同class型 array and containers.

requirementsanalysis

  • implementation一个common 线性搜索function, 可以搜索不同class型 元素
  • supportarray and STLcontainers 搜索
  • 返回找 to 元素 index or iterators
  • such as果元素未找 to , 返回特殊值 or end()iterators

referencecode

#include <iostream>
#include <vector>
#include <list>

using namespace std;

//  for arrayimplementation 线性搜索模板function
template <typename T>
int linearSearch(const T arr[], int size, const T& target) {
    for (int i = 0; i < size; i++) {
        if (arr[i] == target) {
            return i; // 返回找 to  元素 index
        }
    }
    return -1; // 未找 to , 返回-1
}

//  for STLcontainersimplementation 线性搜索模板function
template <typename Container, typename T>
auto linearSearch(const Container& container, const T& target) -> decltype(container.begin()) {
    for (auto it = container.begin(); it != container.end(); ++it) {
        if (*it == target) {
            return it; // 返回找 to  元素 iterators
        }
    }
    return container.end(); // 未找 to , 返回end()iterators
}

int main() {
    // 搜索array
    int intArr[] = {10, 20, 30, 40, 50};
    int intSize = sizeof(intArr) / sizeof(intArr[0]);
    int intTarget = 30;
    int intIndex = linearSearch(intArr, intSize, intTarget);
    if (intIndex != -1) {
        cout << "找 to 整数 " << intTarget << ", index: " << intIndex << endl;
    } else {
        cout << "未找 to 整数 " << intTarget << endl;
    }
    
    // 搜索vector
    vector<string> strVec = {"apple", "banana", "cherry", "date"};
    string strTarget = "cherry";
    auto strIt = linearSearch(strVec, strTarget);
    if (strIt != strVec.end()) {
        cout << "找 to string " << strTarget << ", 位置: " << distance(strVec.begin(), strIt) << endl;
    } else {
        cout << "未找 to string " << strTarget << endl;
    }
    
    // 搜索list
    list<double> doubleList = {1.1, 2.2, 3.3, 4.4, 5.5};
    double doubleTarget = 4.4;
    auto doubleIt = linearSearch(doubleList, doubleTarget);
    if (doubleIt != doubleList.end()) {
        cout << "找 to 双精度数 " << doubleTarget << endl;
    } else {
        cout << "未找 to 双精度数 " << doubleTarget << endl;
    }
    
    return 0;
}

互动练习

练习1: implementation一个common Swapfunction, 用于交换两个不同class型 值.

要求:

  • usingfunction模板implementation
  • support不同class型 parameter
  • in 主functionintest交换整数, 浮点数 and string

练习2: implementation一个common Queueclass模板.

要求:

  • using动态arrayimplementation
  • support入队 (enqueue) , 出队 (dequeue) operation
  • support获取队首元素 (front) and 队尾元素 (back)
  • supportcheckqueue is 否 for 空 (isEmpty) and 获取queue big small (size)
  • in 主functionintest不同class型 queue

练习3: implementation一个common Pairclass模板, 用于store一 for 不同class型 值.

要求:

  • using两个模板parameter
  • providingconstructfunction and 访问器method
  • implementation比较运算符 (==, !=)
  • in 主functionintest不同class型 Pair