C++ 学习杂记02:C++模板编程

模板概述

模板是C++实现泛型编程的核心特性,允许编写与数据类型无关的通用代码。

主要优势:

  • 代码复用

  • 类型安全

  • 编译时多态

  • 性能优化(编译时展开)


函数模板

基本语法

复制代码
复制代码
复制代码
template <typename T>
T add(T a, T b) {
    return a + b;
}

完整示例

复制代码
复制代码
复制代码
#include <iostream>
#include <string>

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

// 2. 多个类型参数的模板
template <typename T1, typename T2>
auto addMixed(T1 a, T2 b) -> decltype(a + b) {
    return a + b;
}

// 3. 非类型模板参数
template <typename T, int size>
T scale(T value) {
    return value * size;
}

// 4. 模板函数重载
template <typename T>
void print(const T& value) {
    std::cout << "Generic: " << value << std::endl;
}

// 字符串特化(函数重载实现)
void print(const char* str) {
    std::cout << "String: \"" << str << "\"" << std::endl;
}

void testFunctionTemplates() {
    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('a', 'z') = " << max('a', 'z') << std::endl;
    
    // 测试混合类型
    std::cout << "addMixed(10, 3.14) = " << addMixed(10, 3.14) << std::endl;
    
    // 测试非类型参数
    std::cout << "scale<int, 5>(10) = " << scale<int, 5>(10) << std::endl;
    
    // 测试函数重载
    print(42);
    print(3.14159);
    print("Hello Template!");
}

输出结果:

复制代码
复制代码
复制代码
=== 函数模板测试 ===
max(3, 5) = 5
max(3.14, 2.71) = 3.14
max('a', 'z') = z
addMixed(10, 3.14) = 13.14
scale<int, 5>(10) = 50
Generic: 42
Generic: 3.14159
String: "Hello Template!"

类模板

基本语法

复制代码
复制代码
复制代码
template <typename T>
class Container {
private:
    T element;
public:
    Container(T value) : element(value) {}
    T get() { return element; }
};

完整示例

复制代码
复制代码
复制代码
#include <iostream>
#include <vector>
#include <string>

// 1. 简单的栈类模板
template <typename T, int MAX_SIZE = 100>
class Stack {
private:
    T data[MAX_SIZE];
    int top;
public:
    Stack() : top(-1) {}
    
    bool push(const T& item) {
        if (top >= MAX_SIZE - 1) return false;
        data[++top] = item;
        return true;
    }
    
    bool pop() {
        if (top < 0) return false;
        --top;
        return true;
    }
    
    T peek() const {
        if (top < 0) throw std::runtime_error("Stack is empty");
        return data[top];
    }
    
    bool isEmpty() const { return top == -1; }
    int size() const { return top + 1; }
    
    void print() const {
        std::cout << "Stack[";
        for (int i = 0; i <= top; ++i) {
            std::cout << data[i];
            if (i < top) std::cout << ", ";
        }
        std::cout << "]" << std::endl;
    }
};

// 2. 键值对模板
template <typename KeyType, typename ValueType>
class Pair {
private:
    KeyType key;
    ValueType value;
public:
    Pair(KeyType k, ValueType v) : key(k), value(v) {}
    
    KeyType getKey() const { return key; }
    ValueType getValue() const { return value; }
    
    void setValue(ValueType v) { value = v; }
    
    void print() const {
        std::cout << "{" << key << ": " << value << "}" << std::endl;
    }
};

// 3. 智能指针(简化版)
template <typename T>
class SmartPtr {
private:
    T* ptr;
public:
    explicit SmartPtr(T* p = nullptr) : ptr(p) {}
    ~SmartPtr() { delete ptr; }
    
    // 禁止拷贝构造和赋值
    SmartPtr(const SmartPtr&) = delete;
    SmartPtr& operator=(const SmartPtr&) = delete;
    
    // 移动语义
    SmartPtr(SmartPtr&& other) noexcept : ptr(other.ptr) {
        other.ptr = nullptr;
    }
    
    SmartPtr& operator=(SmartPtr&& other) noexcept {
        if (this != &other) {
            delete ptr;
            ptr = other.ptr;
            other.ptr = nullptr;
        }
        return *this;
    }
    
    T& operator*() const { return *ptr; }
    T* operator->() const { return ptr; }
    explicit operator bool() const { return ptr != nullptr; }
};

void testClassTemplates() {
    std::cout << "\n=== 类模板测试 ===" << std::endl;
    
    // 测试Stack
    Stack<int, 5> intStack;
    intStack.push(1);
    intStack.push(2);
    intStack.push(3);
    std::cout << "整数栈: ";
    intStack.print();
    std::cout << "栈顶元素: " << intStack.peek() << std::endl;
    
    Stack<std::string> strStack;
    strStack.push("Hello");
    strStack.push("World");
    strStack.push("Template");
    std::cout << "字符串栈: ";
    strStack.print();
    
    // 测试Pair
    Pair<std::string, int> student("Alice", 95);
    Pair<int, double> dataPoint(1, 3.14159);
    std::cout << "学生信息: ";
    student.print();
    std::cout << "数据点: ";
    dataPoint.print();
    
    // 测试SmartPtr
    SmartPtr<int> smartInt(new int(42));
    std::cout << "智能指针值: " << *smartInt << std::endl;
    
    SmartPtr<std::string> smartStr(new std::string("Smart Pointer"));
    std::cout << "智能指针字符串: " << *smartStr << std::endl;
    std::cout << "字符串长度: " << smartStr->length() << std::endl;
}

输出结果:

复制代码
复制代码
复制代码
=== 类模板测试 ===
整数栈: Stack[1, 2, 3]
栈顶元素: 3
字符串栈: Stack[Hello, World, Template]
学生信息: {Alice: 95}
数据点: {1: 3.14159}
智能指针值: 42
智能指针字符串: Smart Pointer
字符串长度: 13

模板特化

完整示例

复制代码
复制代码
复制代码
#include <iostream>
#include <cstring>

// 通用模板
template <typename T>
class TypeInfo {
public:
    static const char* name() { return "Unknown"; }
    static int size() { return sizeof(T); }
};

// 全特化 - int类型
template <>
class TypeInfo<int> {
public:
    static const char* name() { return "int"; }
    static int size() { return sizeof(int); }
};

// 全特化 - double类型
template <>
class TypeInfo<double> {
public:
    static const char* name() { return "double"; }
    static int size() { return sizeof(double); }
};

// 偏特化 - 指针类型
template <typename T>
class TypeInfo<T*> {
public:
    static const char* name() { 
        static std::string name = std::string("pointer to ") + TypeInfo<T>::name();
        return name.c_str();
    }
    static int size() { return sizeof(T*); }
};

// 偏特化 - 数组类型
template <typename T, size_t N>
class TypeInfo<T[N]> {
public:
    static const char* name() { 
        static std::string name = std::string("array[") + std::to_string(N) + "] of " + TypeInfo<T>::name();
        return name.c_str();
    }
    static int size() { return N * sizeof(T); }
};

// 函数模板特化示例
template <typename T>
bool isEqual(T a, T b) {
    return a == b;
}

// 函数模板特化 - 浮点数比较
template <>
bool isEqual<double>(double a, double b) {
    return std::abs(a - b) < 1e-10;
}

void testTemplateSpecialization() {
    std::cout << "\n=== 模板特化测试 ===" << std::endl;
    
    // 测试类型信息
    std::cout << "TypeInfo<int>: " 
              << TypeInfo<int>::name() 
              << ", Size: " << TypeInfo<int>::size() << std::endl;
    
    std::cout << "TypeInfo<double>: " 
              << TypeInfo<double>::name() 
              << ", Size: " << TypeInfo<double>::size() << std::endl;
    
    std::cout << "TypeInfo<int*>: " 
              << TypeInfo<int*>::name() 
              << ", Size: " << TypeInfo<int*>::size() << std::endl;
    
    std::cout << "TypeInfo<int[5]>: " 
              << TypeInfo<int[5]>::name() 
              << ", Size: " << TypeInfo<int[5]>::size() << std::endl;
    
    // 测试函数模板特化
    std::cout << "\n浮点数比较测试:" << std::endl;
    double d1 = 1.0 / 3.0;
    double d2 = 0.3333333333333333;
    double d3 = 0.34;
    
    std::cout << "isEqual(1, 1) = " << isEqual(1, 1) << std::endl;
    std::cout << "isEqual(1.0, 1.0) = " << isEqual(1.0, 1.0) << std::endl;
    std::cout << "isEqual(d1, d2) = " << isEqual(d1, d2) << std::endl;
    std::cout << "isEqual(d1, d3) = " << isEqual(d1, d3) << std::endl;
}

输出结果:

复制代码
复制代码
复制代码
=== 模板特化测试 ===
TypeInfo<int>: int, Size: 4
TypeInfo<double>: double, Size: 8
TypeInfo<int*>: pointer to int, Size: 8
TypeInfo<int[5]>: array[5] of int, Size: 20

浮点数比较测试:
isEqual(1, 1) = 1
isEqual(1.0, 1.0) = 1
isEqual(d1, d2) = 1
isEqual(d1, d3) = 0

模板元编程

复制代码
复制代码
复制代码
#include <iostream>

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

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

// 编译时判断素数
template <int N, int D = N - 1>
struct IsPrime {
    static const bool value = (N % D != 0) && IsPrime<N, D - 1>::value;
};

template <int N>
struct IsPrime<N, 1> {
    static const bool value = true;
};

template <int N>
struct IsPrime<N, 0> {
    static const bool value = false;
};

// 编译时斐波那契数列
template <int N>
struct Fibonacci {
    static const int value = Fibonacci<N - 1>::value + Fibonacci<N - 2>::value;
};

template <>
struct Fibonacci<0> {
    static const int value = 0;
};

template <>
struct Fibonacci<1> {
    static const int value = 1;
};

void testTemplateMetaprogramming() {
    std::cout << "\n=== 模板元编程测试 ===" << std::endl;
    
    std::cout << "编译时计算:" << std::endl;
    std::cout << "Factorial<5>::value = " << Factorial<5>::value << std::endl;
    std::cout << "Factorial<10>::value = " << Factorial<10>::value << std::endl;
    
    std::cout << "\n编译时素数判断:" << std::endl;
    std::cout << "IsPrime<2>::value = " << IsPrime<2>::value << std::endl;
    std::cout << "IsPrime<13>::value = " << IsPrime<13>::value << std::endl;
    std::cout << "IsPrime<15>::value = " << IsPrime<15>::value << std::endl;
    std::cout << "IsPrime<97>::value = " << IsPrime<97>::value << std::endl;
    
    std::cout << "\n斐波那契数列:" << std::endl;
    std::cout << "Fibonacci<0>::value = " << Fibonacci<0>::value << std::endl;
    std::cout << "Fibonacci<5>::value = " << Fibonacci<5>::value << std::endl;
    std::cout << "Fibonacci<10>::value = " << Fibonacci<10>::value << std::endl;
}

输出结果:

复制代码
复制代码
复制代码
=== 模板元编程测试 ===
编译时计算:
Factorial<5>::value = 120
Factorial<10>::value = 3628800

编译时素数判断:
IsPrime<2>::value = 1
IsPrime<13>::value = 1
IsPrime<15>::value = 0
IsPrime<97>::value = 1

斐波那契数列:
Fibonacci<0>::value = 0
Fibonacci<5>::value = 5
Fibonacci<10>::value = 55

可变参数模板

复制代码
复制代码
复制代码
#include <iostream>
#include <string>

// 基本情况
void printAll() {
    std::cout << std::endl;
}

// 可变参数模板
template <typename T, typename... Args>
void printAll(T first, Args... args) {
    std::cout << first;
    if (sizeof...(args) > 0) {
        std::cout << ", ";
    }
    printAll(args...);
}

// 编译时计算参数个数
template <typename... Args>
struct CountArgs {
    static const int value = sizeof...(Args);
};

// 求和模板
template <typename... Args>
auto sumAll(Args... args) {
    return (args + ...);  // C++17折叠表达式
}

// 构造任意类型元组
template <typename... Args>
void makeTuple(Args... args) {
    std::cout << "Tuple with " << sizeof...(args) << " elements created" << std::endl;
}

void testVariadicTemplates() {
    std::cout << "\n=== 可变参数模板测试 ===" << std::endl;
    
    std::cout << "printAll测试:" << std::endl;
    printAll(1, 2, 3, 4, 5);
    printAll(1, 2.5, "hello", 'A', true);
    
    std::cout << "\n参数计数测试:" << std::endl;
    std::cout << "CountArgs<int, char, double>::value = " 
              << CountArgs<int, char, double>::value << std::endl;
    std::cout << "CountArgs<>::value = " << CountArgs<>::value << std::endl;
    
    std::cout << "\n求和测试:" << std::endl;
    std::cout << "sumAll(1, 2, 3, 4, 5) = " << sumAll(1, 2, 3, 4, 5) << std::endl;
    std::cout << "sumAll(1.1, 2.2, 3.3) = " << sumAll(1.1, 2.2, 3.3) << std::endl;
    
    std::cout << "\n元组测试:" << std::endl;
    makeTuple(1, "test", 3.14, 'X');
}

输出结果:

复制代码
复制代码
复制代码
=== 可变参数模板测试 ===
printAll测试:
1, 2, 3, 4, 5
1, 2.5, hello, A, 1

参数计数测试:
CountArgs<int, char, double>::value = 3
CountArgs<>::value = 0

求和测试:
sumAll(1, 2, 3, 4, 5) = 15
sumAll(1.1, 2.2, 3.3) = 6.6

元组测试:
Tuple with 4 elements created

注意事项

  1. 编译时代价:模板代码在编译时展开,可能导致编译时间增加

  2. 代码膨胀:每个不同类型的实例化都会生成独立的代码

  3. 错误信息:模板错误信息通常难以理解

  4. 分离编译:模板通常需要在头文件中实现

  5. 类型约束:C++20引入concept来改进类型约束

复制代码
复制代码
复制代码
// C++20 Concepts示例
#include <concepts>

template <typename T>
concept Addable = requires(T a, T b) {
    { a + b } -> std::convertible_to<T>;
};

template <Addable T>
T add(T a, T b) {
    return a + b;
}

综合测试程序

复制代码
复制代码
复制代码
int main() {
    testFunctionTemplates();
    testClassTemplates();
    testTemplateSpecialization();
    testTemplateMetaprogramming();
    testVariadicTemplates();
    
    std::cout << "\n=== 所有测试完成 ===" << std::endl;
    return 0;
}

总结

C++模板提供了强大的泛型编程能力:

  1. 函数模板:编写与类型无关的函数

  2. 类模板:创建通用的数据结构

  3. 模板特化:为特定类型提供优化实现

  4. 模板元编程:编译时计算和类型计算

  5. 可变参数模板:处理任意数量和类型的参数

模板是C++标准库(STL)的基石,熟练掌握模板编程是成为高级C++开发者的关键技能。

相关推荐
楼田莉子2 小时前
仿muduo的高并发服务器——前置知识讲解和时间轮模块
服务器·开发语言·c++·后端·学习
OYangxf2 小时前
C++中的回调函数:从函数指针到现代可调用对象
c++
qeen872 小时前
【数据结构】队列及其C语言模拟实现
c语言·数据结构·c++·学习·队列
田野追逐星光2 小时前
C++继承 -- 讲解超详细(上)
c++·算法
fish_xk2 小时前
c++的list
开发语言·c++·list
浪浪小洋12 小时前
c++ qt课设定制
开发语言·c++
charlie11451419113 小时前
嵌入式C++工程实践第16篇:第四次重构 —— LED模板,从通用GPIO到专用抽象
c语言·开发语言·c++·驱动开发·嵌入式硬件·重构
handler0113 小时前
Linux: 基本指令知识点(2)
linux·服务器·c语言·c++·笔记·学习
香蕉鼠片15 小时前
MFC是什么
c++·mfc