Skip to content

C++ 模板

概述

模板(Template)是C++的强大特性,允许编写与类型无关的泛型代码。模板实现了编译时多态,提供了类型安全的代码重用机制。本章介绍函数模板、类模板、模板特化、SFINAE等高级模板技术。

🔧 函数模板

基础函数模板

cpp
#include <iostream>
#include <string>
#include <vector>

// 基础函数模板
template<typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

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

// 非类型模板参数
template<typename T, int Size>
void printArray(const T (&arr)[Size]) {
    std::cout << "数组大小: " << Size << ", 内容: ";
    for (int i = 0; i < Size; ++i) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
}

// 变参模板
template<typename... Args>
void print(Args... args) {
    ((std::cout << args << " "), ...);  // C++17折叠表达式
    std::cout << std::endl;
}

int main() {
    std::cout << "=== 函数模板 ===" << std::endl;
    
    // 类型自动推导
    std::cout << "max(3, 5) = " << max(3, 5) << std::endl;
    std::cout << "max(3.14, 2.71) = " << max(3.14, 2.71) << std::endl;
    std::cout << "max(\"hello\", \"world\") = " << max(std::string("hello"), std::string("world")) << std::endl;
    
    // 显式指定类型
    std::cout << "max<double>(3, 5.5) = " << max<double>(3, 5.5) << std::endl;
    
    // 多类型模板
    auto result = add(10, 3.14);
    std::cout << "add(10, 3.14) = " << result << std::endl;
    
    // 非类型参数
    int arr[] = {1, 2, 3, 4, 5};
    printArray(arr);
    
    // 变参模板
    print("Hello", 42, 3.14, "World");
    
    return 0;
}

模板特化

cpp
#include <iostream>
#include <string>
#include <vector>

// 主模板
template<typename T>
class Container {
private:
    std::vector<T> data_;
    
public:
    void add(const T& item) {
        data_.push_back(item);
    }
    
    void print() const {
        std::cout << "通用容器: ";
        for (const auto& item : data_) {
            std::cout << item << " ";
        }
        std::cout << std::endl;
    }
    
    size_t size() const { return data_.size(); }
};

// 全特化
template<>
class Container<bool> {
private:
    std::vector<bool> data_;
    
public:
    void add(bool item) {
        data_.push_back(item);
    }
    
    void print() const {
        std::cout << "布尔容器: ";
        for (bool item : data_) {
            std::cout << (item ? "true" : "false") << " ";
        }
        std::cout << std::endl;
    }
    
    size_t size() const { return data_.size(); }
};

// 偏特化
template<typename T>
class Container<T*> {
private:
    std::vector<T*> data_;
    
public:
    void add(T* item) {
        data_.push_back(item);
    }
    
    void print() const {
        std::cout << "指针容器: ";
        for (const auto& ptr : data_) {
            if (ptr) {
                std::cout << *ptr << " ";
            } else {
                std::cout << "null ";
            }
        }
        std::cout << std::endl;
    }
    
    size_t size() const { return data_.size(); }
};

int main() {
    std::cout << "=== 模板特化 ===" << std::endl;
    
    // 主模板
    Container<int> intContainer;
    intContainer.add(1);
    intContainer.add(2);
    intContainer.add(3);
    intContainer.print();
    
    // 全特化
    Container<bool> boolContainer;
    boolContainer.add(true);
    boolContainer.add(false);
    boolContainer.add(true);
    boolContainer.print();
    
    // 偏特化
    Container<int*> ptrContainer;
    int a = 10, b = 20, c = 30;
    ptrContainer.add(&a);
    ptrContainer.add(&b);
    ptrContainer.add(&c);
    ptrContainer.print();
    
    return 0;
}

🏗️ 类模板

基础类模板

cpp
#include <iostream>
#include <memory>

template<typename T>
class Stack {
private:
    struct Node {
        T data;
        std::unique_ptr<Node> next;
        
        Node(const T& value) : data(value), next(nullptr) {}
    };
    
    std::unique_ptr<Node> top_;
    size_t size_;
    
public:
    Stack() : top_(nullptr), size_(0) {}
    
    // 移动构造函数
    Stack(Stack&& other) noexcept 
        : top_(std::move(other.top_)), size_(other.size_) {
        other.size_ = 0;
    }
    
    // 移动赋值运算符
    Stack& operator=(Stack&& other) noexcept {
        if (this != &other) {
            top_ = std::move(other.top_);
            size_ = other.size_;
            other.size_ = 0;
        }
        return *this;
    }
    
    void push(const T& value) {
        auto new_node = std::make_unique<Node>(value);
        new_node->next = std::move(top_);
        top_ = std::move(new_node);
        ++size_;
    }
    
    void pop() {
        if (top_) {
            top_ = std::move(top_->next);
            --size_;
        }
    }
    
    const T& top() const {
        if (!top_) {
            throw std::runtime_error("栈为空");
        }
        return top_->data;
    }
    
    bool empty() const { return top_ == nullptr; }
    size_t size() const { return size_; }
};

// 模板成员函数
template<typename T>
class Vector {
private:
    T* data_;
    size_t size_;
    size_t capacity_;
    
public:
    Vector() : data_(nullptr), size_(0), capacity_(0) {}
    
    ~Vector() {
        delete[] data_;
    }
    
    template<typename InputIt>
    Vector(InputIt first, InputIt last) : Vector() {
        while (first != last) {
            push_back(*first++);
        }
    }
    
    void push_back(const T& value) {
        if (size_ == capacity_) {
            reserve(capacity_ == 0 ? 1 : capacity_ * 2);
        }
        data_[size_++] = value;
    }
    
    void reserve(size_t new_capacity) {
        if (new_capacity > capacity_) {
            T* new_data = new T[new_capacity];
            for (size_t i = 0; i < size_; ++i) {
                new_data[i] = std::move(data_[i]);
            }
            delete[] data_;
            data_ = new_data;
            capacity_ = new_capacity;
        }
    }
    
    T& operator[](size_t index) { return data_[index]; }
    const T& operator[](size_t index) const { return data_[index]; }
    
    size_t size() const { return size_; }
    bool empty() const { return size_ == 0; }
};

int main() {
    std::cout << "=== 类模板 ===" << std::endl;
    
    // Stack测试
    Stack<int> intStack;
    intStack.push(1);
    intStack.push(2);
    intStack.push(3);
    
    std::cout << "栈内容: ";
    while (!intStack.empty()) {
        std::cout << intStack.top() << " ";
        intStack.pop();
    }
    std::cout << std::endl;
    
    // Vector测试
    Vector<std::string> strVector;
    strVector.push_back("Hello");
    strVector.push_back("World");
    strVector.push_back("C++");
    
    std::cout << "向量内容: ";
    for (size_t i = 0; i < strVector.size(); ++i) {
        std::cout << strVector[i] << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

🔍 SFINAE和概念

SFINAE技术

cpp
#include <iostream>
#include <type_traits>
#include <string>

// SFINAE: Substitution Failure Is Not An Error

// 检测类型是否有begin()方法
template<typename T>
class has_begin {
private:
    template<typename U>
    static auto test(int) -> decltype(std::declval<U>().begin(), std::true_type{});
    
    template<typename>
    static std::false_type test(...);
    
public:
    static constexpr bool value = decltype(test<T>(0))::value;
};

// 使用std::enable_if进行条件编译
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
process(T value) {
    std::cout << "处理数值类型: " << value << std::endl;
    return value * 2;
}

template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value, T>::type
process(T value) {
    std::cout << "处理非数值类型: " << value << std::endl;
    return value;
}

// 条件实例化
template<typename Container>
typename std::enable_if<has_begin<Container>::value>::type
printContainer(const Container& container) {
    std::cout << "可迭代容器: ";
    for (const auto& item : container) {
        std::cout << item << " ";
    }
    std::cout << std::endl;
}

template<typename T>
typename std::enable_if<!has_begin<T>::value>::type
printContainer(const T& item) {
    std::cout << "单个元素: " << item << std::endl;
}

int main() {
    std::cout << "=== SFINAE技术 ===" << std::endl;
    
    // 类型特征检测
    std::cout << "std::vector<int> has begin(): " << has_begin<std::vector<int>>::value << std::endl;
    std::cout << "int has begin(): " << has_begin<int>::value << std::endl;
    
    // 条件编译
    auto result1 = process(42);
    auto result2 = process(std::string("Hello"));
    
    std::cout << "处理结果: " << result1 << ", " << result2 << std::endl;
    
    // 条件实例化
    std::vector<int> vec = {1, 2, 3, 4, 5};
    printContainer(vec);
    printContainer(42);
    
    return 0;
}

📋 模板元编程

编译时计算

cpp
#include <iostream>
#include <type_traits>

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

template<>
struct Factorial<0> {
    static constexpr int value = 1;
};

// 编译时类型列表
template<typename... Types>
struct TypeList {};

template<typename List>
struct Length;

template<typename... Types>
struct Length<TypeList<Types...>> {
    static constexpr size_t value = sizeof...(Types);
};

// 编译时条件选择
template<bool Condition, typename TrueType, typename FalseType>
struct Conditional {
    using type = TrueType;
};

template<typename TrueType, typename FalseType>
struct Conditional<false, TrueType, FalseType> {
    using type = FalseType;
};

// 类型萃取
template<typename T>
struct RemovePointer {
    using type = T;
};

template<typename T>
struct RemovePointer<T*> {
    using type = T;
};

template<typename T>
using RemovePointer_t = typename RemovePointer<T>::type;

// 编译时循环展开
template<size_t N>
struct Loop {
    template<typename Func>
    static void execute(Func&& func) {
        func(N - 1);
        Loop<N - 1>::execute(std::forward<Func>(func));
    }
};

template<>
struct Loop<0> {
    template<typename Func>
    static void execute(Func&&) {}
};

int main() {
    std::cout << "=== 模板元编程 ===" << std::endl;
    
    // 编译时计算
    constexpr int fact5 = Factorial<5>::value;
    std::cout << "5! = " << fact5 << std::endl;
    
    // 类型列表长度
    using MyTypes = TypeList<int, double, std::string, char>;
    constexpr size_t length = Length<MyTypes>::value;
    std::cout << "类型列表长度: " << length << std::endl;
    
    // 条件类型选择
    using SelectedType = Conditional<true, int, double>::type;
    static_assert(std::is_same_v<SelectedType, int>);
    std::cout << "条件选择成功" << std::endl;
    
    // 类型萃取
    using IntType = RemovePointer_t<int*>;
    static_assert(std::is_same_v<IntType, int>);
    std::cout << "指针类型萃取成功" << std::endl;
    
    // 编译时循环
    std::cout << "编译时循环展开: ";
    Loop<5>::execute([](size_t i) {
        std::cout << i << " ";
    });
    std::cout << std::endl;
    
    return 0;
}

总结

C++模板是强大的泛型编程工具,支持编译时多态和元编程:

模板类型

  • 函数模板: 泛型函数
  • 类模板: 泛型类
  • 变参模板: 可变参数
  • 模板特化: 特定类型优化

高级技术

技术用途特点
SFINAE条件编译类型检测
元编程编译时计算零运行时开销
类型萃取类型操作编译时类型推导
概念类型约束C++20特性

最佳实践

  • 使用auto减少模板复杂度
  • 合理使用模板特化
  • 利用SFINAE进行类型检测
  • 避免过度使用模板元编程
  • 提供清晰的错误信息

模板让C++具有强大的泛型编程能力,是现代C++的核心特性。

本站内容仅供学习和研究使用。