Skip to content

模板

模板是C++泛型编程的核心,允许编写与类型无关的代码。本章将介绍函数模板、类模板和模板的高级用法。

函数模板

cpp
#include <iostream>
#include <string>
using namespace std;

// ============ 基本函数模板 ============

// 定义函数模板
// template<typename T> 或 template<class T>
template<typename T>
T maxValue(T a, T b) {
    return (a > b) ? a : b;
}

// 多个模板参数
template<typename T1, typename T2>
auto add(T1 a, T2 b) -> decltype(a + b) {
    return a + b;
}

// C++14:自动推导返回类型
template<typename T1, typename T2>
auto multiply(T1 a, T2 b) {
    return a * b;
}

// ============ 模板特化 ============

// 针对特定类型的特化版本
template<>
const char* maxValue<const char*>(const char* a, const char* b) {
    return (strcmp(a, b) > 0) ? a : b;
}

// ============ 非类型模板参数 ============

template<typename T, int size>
class FixedArray {
private:
    T data[size];
    
public:
    int getSize() { return size; }
    
    T& operator[](int index) {
        return data[index];
    }
};

int main() {
    // 隐式实例化(自动推导类型)
    cout << "max(10, 20) = " << maxValue(10, 20) << endl;
    cout << "max(3.14, 2.71) = " << maxValue(3.14, 2.71) << endl;
    cout << "max('a', 'z') = " << maxValue('a', 'z') << endl;
    
    // 显式指定类型
    cout << "max<double>(10, 20.5) = " << maxValue<double>(10, 20.5) << endl;
    
    // 多模板参数
    cout << "\nadd(10, 20.5) = " << add(10, 20.5) << endl;
    cout << "multiply(3, 4.5) = " << multiply(3, 4.5) << endl;
    
    // 非类型模板参数
    FixedArray<int, 5> arr;
    for (int i = 0; i < arr.getSize(); i++) {
        arr[i] = i * 10;
    }
    
    cout << "\nFixedArray: ";
    for (int i = 0; i < arr.getSize(); i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    
    return 0;
}

类模板

cpp
#include <iostream>
#include <stdexcept>
using namespace std;

// ============ 基本类模板 ============

template<typename T>
class Container {
private:
    T* data;
    int size;
    int capacity;
    
public:
    // 构造函数
    Container(int cap = 10) : capacity(cap), size(0) {
        data = new T[capacity];
    }
    
    // 析构函数
    ~Container() {
        delete[] data;
    }
    
    // 添加元素
    void add(const T& value) {
        if (size >= capacity) {
            // 扩容
            int newCapacity = capacity * 2;
            T* newData = new T[newCapacity];
            for (int i = 0; i < size; i++) {
                newData[i] = data[i];
            }
            delete[] data;
            data = newData;
            capacity = newCapacity;
        }
        data[size++] = value;
    }
    
    // 获取元素
    T& get(int index) {
        if (index < 0 || index >= size) {
            throw out_of_range("索引越界");
        }
        return data[index];
    }
    
    // 获取大小
    int getSize() const { return size; }
    
    // 下标运算符
    T& operator[](int index) {
        return get(index);
    }
    
    const T& operator[](int index) const {
        if (index < 0 || index >= size) {
            throw out_of_range("索引越界");
        }
        return data[index];
    }
};

// ============ 类模板特化 ============

// 全特化
template<>
class Container<bool> {
private:
    unsigned char* data;
    int size;
    int capacity;
    
public:
    Container(int cap = 10) : capacity(cap), size(0) {
        int bytes = (cap + 7) / 8;
        data = new unsigned char[bytes]();
    }
    
    ~Container() {
        delete[] data;
    }
    
    void add(bool value) {
        int byteIndex = size / 8;
        int bitIndex = size % 8;
        
        if (value) {
            data[byteIndex] |= (1 << bitIndex);
        } else {
            data[byteIndex] &= ~(1 << bitIndex);
        }
        size++;
    }
    
    bool get(int index) {
        int byteIndex = index / 8;
        int bitIndex = index % 8;
        return (data[byteIndex] >> bitIndex) & 1;
    }
    
    int getSize() const { return size; }
};

int main() {
    // 使用类模板
    Container<int> intContainer;
    intContainer.add(10);
    intContainer.add(20);
    intContainer.add(30);
    
    cout << "int容器: ";
    for (int i = 0; i < intContainer.getSize(); i++) {
        cout << intContainer[i] << " ";
    }
    cout << endl;
    
    // 字符串容器
    Container<string> strContainer;
    strContainer.add("Hello");
    strContainer.add("World");
    strContainer.add("C++");
    
    cout << "string容器: ";
    for (int i = 0; i < strContainer.getSize(); i++) {
        cout << strContainer[i] << " ";
    }
    cout << endl;
    
    // bool容器(使用特化版本)
    Container<bool> boolContainer;
    boolContainer.add(true);
    boolContainer.add(false);
    boolContainer.add(true);
    
    cout << "bool容器: ";
    for (int i = 0; i < boolContainer.getSize(); i++) {
        cout << boolContainer.get(i) << " ";
    }
    cout << endl;
    
    return 0;
}

模板高级用法

cpp
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;

// ============ 可变参数模板 ============

// 递归终止条件
template<typename T>
void print(T value) {
    cout << value << endl;
}

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

// C++17:折叠表达式
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);  // 一元右折叠
}

template<typename... Args>
auto product(Args... args) {
    return (... * args);  // 一元左折叠
}

// ============ 模板元编程 ============

// 编译时计算阶乘
template<int N>
struct Factorial {
    static const int value = N * Factorial<N - 1>::value;
};

// 特化:终止条件
template<>
struct Factorial<0> {
    static const int value = 1;
};

// 编译时判断类型
template<typename T>
void process(T value) {
    if constexpr (is_integral<T>::value) {  // C++17
        cout << "整数类型: " << value << endl;
    } else if constexpr (is_floating_point<T>::value) {
        cout << "浮点类型: " << value << endl;
    } else if constexpr (is_pointer<T>::value) {
        cout << "指针类型: " << *value << endl;
    } else {
        cout << "其他类型: " << value << endl;
    }
}

// ============ SFINAE ============

// 只对有size()方法的类型有效
template<typename T>
auto getSize(const T& container) -> decltype(container.size()) {
    return container.size();
}

// 只对数组类型有效
template<typename T, size_t N>
size_t getSize(const T (&)[N]) {
    return N;
}

// ============ 完美转发 ============

template<typename T>
void wrapper(T&& arg) {
    // forward保持参数的值类别
    process(forward<T>(arg));
}

int main() {
    // 可变参数模板
    cout << "===== 可变参数模板 =====" << endl;
    print(1, 2.5, "hello", 'c');
    
    cout << "\nsum(1, 2, 3, 4, 5) = " << sum(1, 2, 3, 4, 5) << endl;
    cout << "product(1, 2, 3, 4, 5) = " << product(1, 2, 3, 4, 5) << endl;
    
    // 模板元编程
    cout << "\n===== 模板元编程 =====" << endl;
    cout << "5! = " << Factorial<5>::value << endl;
    cout << "10! = " << Factorial<10>::value << endl;
    
    // 类型判断
    cout << "\n===== 类型判断 =====" << endl;
    process(42);
    process(3.14);
    process("hello");
    
    int x = 100;
    process(&x);
    
    // SFINAE
    cout << "\n===== SFINAE =====" << endl;
    int arr[] = {1, 2, 3, 4, 5};
    string str = "hello";
    
    cout << "数组大小: " << getSize(arr) << endl;
    cout << "字符串大小: " << getSize(str) << endl;
    
    return 0;
}

本章小结

本章学习了:

  • 函数模板:定义、实例化、特化
  • 类模板:定义、成员函数、特化
  • 可变参数模板:参数包、折叠表达式
  • 模板元编程:编译时计算、类型判断
  • SFINAE:替换失败不是错误
  • 完美转发:forward保持值类别

下一章,我们将学习STL标准模板库,了解C++标准库的强大功能。