C++学习笔记-模板

模板是C++中实现泛型编程的核心机制,允许编写与类型无关的代码。模板在编译时进行实例化,为不同的类型生成对应的代码,提供了类型安全的泛型解决方案。

函数模板的基本概念

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <string>

// 传统方式:为每种类型写一个函数
/*
void Print(int value)
{
    std::cout << value << std::endl;
}

void Print(std::string value)
{
    std::cout << value << std::endl;
}

void Print(float value)
{
    std::cout << value << std::endl;
}
*/

// 使用模板:一个简单的模板,typename表示类型参数,T是类型名称
template<typename T>
void Print(T value)
{
    std::cout << value << std::endl;
}

int main()
{
    Print(5);        // T = int
    Print("Hello");  // T = const char*
    Print(5.5f);     // T = float
    
    // 显式指定模板参数
    Print<int>(42);
    Print<std::string>("World");
    
    return 0;
}

类模板的基本使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// 模板应用在类上的例子
template<typename T, int N>
class Array
{
private:
    T m_Array[N];
    
public:
    Array()
    {
        for (int i = 0; i < N; ++i)
            m_Array[i] = T{};  // 默认初始化
    }
    
    T& operator[](int index)
    {
        return m_Array[index];
    }
    
    const T& operator[](int index) const
    {
        return m_Array[index];
    }
    
    int GetSize() const { return N; }
    
    void Fill(const T& value)
    {
        for (int i = 0; i < N; ++i)
            m_Array[i] = value;
    }
    
    void Print() const
    {
        std::cout << "[";
        for (int i = 0; i < N; ++i)
        {
            std::cout << m_Array[i];
            if (i < N - 1) std::cout << ", ";
        }
        std::cout << "]" << std::endl;
    }
};

int main()
{
    Array<int, 5> intArray;
    std::cout << "Array size: " << intArray.GetSize() << std::endl;
    
    // 填充数组
    for (int i = 0; i < intArray.GetSize(); ++i)
    {
        intArray[i] = i * 10;
    }
    
    intArray.Print();
    
    // 字符串数组
    Array<std::string, 3> stringArray;
    stringArray[0] = "Hello";
    stringArray[1] = "World";
    stringArray[2] = "!";
    stringArray.Print();
    
    // 浮点数组
    Array<float, 4> floatArray;
    floatArray.Fill(3.14f);
    floatArray.Print();
    
    return 0;
}

多个模板参数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
template<typename T, typename U>
class Pair
{
private:
    T m_First;
    U m_Second;
    
public:
    Pair(const T& first, const U& second) : m_First(first), m_Second(second) {}
    
    T& GetFirst() { return m_First; }
    const T& GetFirst() const { return m_First; }
    
    U& GetSecond() { return m_Second; }
    const U& GetSecond() const { return m_Second; }
    
    void Print() const
    {
        std::cout << "(" << m_First << ", " << m_Second << ")" << std::endl;
    }
};

// 函数模板也可以有多个参数
template<typename T, typename U>
auto Add(T a, U b) -> decltype(a + b)  // C++11 trailing return type
{
    return a + b;
}

// C++14 简化版本
template<typename T, typename U>
auto Multiply(T a, U b)
{
    return a * b;
}

int main()
{
    Pair<std::string, int> nameAge("Alice", 25);
    nameAge.Print();
    
    Pair<int, double> coordinates(10, 3.14);
    coordinates.Print();
    
    // 混合类型运算
    auto result1 = Add(5, 3.14);        // int + double = double
    auto result2 = Multiply(2.5f, 4);   // float * int = float
    
    std::cout << "5 + 3.14 = " << result1 << std::endl;
    std::cout << "2.5 * 4 = " << result2 << std::endl;
    
    return 0;
}

模板特化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <string>

// 通用模板
template<typename T>
class Storage
{
private:
    T m_Data;
    
public:
    Storage(const T& data) : m_Data(data) {}
    
    void Print() const
    {
        std::cout << "Generic storage: " << m_Data << std::endl;
    }
    
    T GetData() const { return m_Data; }
};

// 完全特化:为bool类型提供特殊实现
template<>
class Storage<bool>
{
private:
    bool m_Data;
    
public:
    Storage(bool data) : m_Data(data) {}
    
    void Print() const
    {
        std::cout << "Bool storage: " << (m_Data ? "true" : "false") << std::endl;
    }
    
    bool GetData() const { return m_Data; }
    
    void Toggle() { m_Data = !m_Data; }  // bool特有的方法
};

// 偏特化:为指针类型提供特殊实现
template<typename T>
class Storage<T*>
{
private:
    T* m_Data;
    
public:
    Storage(T* data) : m_Data(data) {}
    
    void Print() const
    {
        if (m_Data)
            std::cout << "Pointer storage: " << *m_Data << " (address: " << m_Data << ")" << std::endl;
        else
            std::cout << "Pointer storage: nullptr" << std::endl;
    }
    
    T* GetData() const { return m_Data; }
    
    T& Dereference() const { return *m_Data; }  // 指针特有的方法
};

int main()
{
    // 使用通用模板
    Storage<int> intStorage(42);
    intStorage.Print();
    
    Storage<std::string> stringStorage("Hello");
    stringStorage.Print();
    
    // 使用bool特化
    Storage<bool> boolStorage(true);
    boolStorage.Print();
    boolStorage.Toggle();
    boolStorage.Print();
    
    // 使用指针特化
    int value = 100;
    Storage<int*> ptrStorage(&value);
    ptrStorage.Print();
    
    return 0;
}

可变参数模板(C++11)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>

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

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

// 使用fold expression(C++17)
template<typename... Args>
void PrintAllFold(Args&&... args)
{
    ((std::cout << args << " "), ...);
    std::cout << std::endl;
}

// 可变参数类模板
template<typename... Types>
class Tuple;

// 空tuple特化
template<>
class Tuple<>
{
public:
    static constexpr size_t size() { return 0; }
};

// 递归定义
template<typename Head, typename... Tail>
class Tuple<Head, Tail...>
{
private:
    Head m_Head;
    Tuple<Tail...> m_Tail;
    
public:
    Tuple(Head head, Tail... tail) : m_Head(head), m_Tail(tail...) {}
    
    static constexpr size_t size() { return 1 + sizeof...(Tail); }
    
    Head& head() { return m_Head; }
    const Head& head() const { return m_Head; }
    
    Tuple<Tail...>& tail() { return m_Tail; }
    const Tuple<Tail...>& tail() const { return m_Tail; }
};

int main()
{
    std::cout << "=== Variadic Templates ===" << std::endl;
    
    PrintAll(1, 2.5, "hello", 'c');
    
    std::cout << "\n=== Fold Expression (C++17) ===" << std::endl;
    PrintAllFold(1, 2.5, "hello", 'c');
    
    std::cout << "\n=== Custom Tuple ===" << std::endl;
    Tuple<int, double, std::string> myTuple(42, 3.14, "world");
    std::cout << "Tuple size: " << myTuple.size() << std::endl;
    std::cout << "Head: " << myTuple.head() << std::endl;
    
    return 0;
}

模板约束和概念(C++20)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <concepts>
#include <iostream>

// 定义概念
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

template<typename T>
concept Printable = requires(T t) {
    std::cout << t;
};

// 使用概念约束模板
template<Numeric T>
T Add(T a, T b)
{
    return a + b;
}

template<Printable T>
void SafePrint(const T& value)
{
    std::cout << "Printing: " << value << std::endl;
}

// 更复杂的概念
template<typename T>
concept Container = requires(T t) {
    t.begin();
    t.end();
    t.size();
};

template<Container C>
void PrintContainer(const C& container)
{
    std::cout << "Container size: " << container.size() << std::endl;
    std::cout << "Elements: ";
    for (const auto& element : container)
    {
        std::cout << element << " ";
    }
    std::cout << std::endl;
}

int main()
{
    // 使用约束的模板
    auto result1 = Add(5, 10);        // OK: int是Numeric
    auto result2 = Add(3.14, 2.86);   // OK: double是Numeric
    // auto result3 = Add("a", "b");  // 编译错误: string不是Numeric
    
    SafePrint(42);
    SafePrint("Hello");
    SafePrint(3.14);
    
    std::vector<int> vec = {1, 2, 3, 4, 5};
    PrintContainer(vec);
    
    return 0;
}

模板元编程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>

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

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

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

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

template<>
struct IsPrime<1, 0>
{
    static constexpr bool value = false;
};

// 类型特征
template<typename T>
struct TypeInfo
{
    static constexpr bool is_pointer = false;
    static constexpr bool is_reference = false;
    static constexpr const char* name = "unknown";
};

template<typename T>
struct TypeInfo<T*>
{
    static constexpr bool is_pointer = true;
    static constexpr bool is_reference = false;
    static constexpr const char* name = "pointer";
};

template<typename T>
struct TypeInfo<T&>
{
    static constexpr bool is_pointer = false;
    static constexpr bool is_reference = true;
    static constexpr const char* name = "reference";
};

int main()
{
    // 编译时计算
    constexpr int fact5 = Factorial<5>::value;
    constexpr bool is17Prime = IsPrime<17>::value;
    constexpr bool is16Prime = IsPrime<16>::value;
    
    std::cout << "5! = " << fact5 << std::endl;
    std::cout << "17 is prime: " << is17Prime << std::endl;
    std::cout << "16 is prime: " << is16Prime << std::endl;
    
    // 类型信息
    std::cout << "int* is pointer: " << TypeInfo<int*>::is_pointer << std::endl;
    std::cout << "int& is reference: " << TypeInfo<int&>::is_reference << std::endl;
    
    return 0;
}

实际应用:智能指针模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
template<typename T>
class UniquePtr
{
private:
    T* m_Ptr;
    
public:
    explicit UniquePtr(T* ptr = nullptr) : m_Ptr(ptr) {}
    
    ~UniquePtr()
    {
        delete m_Ptr;
    }
    
    // 禁用拷贝
    UniquePtr(const UniquePtr&) = delete;
    UniquePtr& operator=(const UniquePtr&) = delete;
    
    // 移动构造和赋值
    UniquePtr(UniquePtr&& other) noexcept : m_Ptr(other.m_Ptr)
    {
        other.m_Ptr = nullptr;
    }
    
    UniquePtr& operator=(UniquePtr&& other) noexcept
    {
        if (this != &other)
        {
            delete m_Ptr;
            m_Ptr = other.m_Ptr;
            other.m_Ptr = nullptr;
        }
        return *this;
    }
    
    T& operator*() const { return *m_Ptr; }
    T* operator->() const { return m_Ptr; }
    
    T* Get() const { return m_Ptr; }
    
    T* Release()
    {
        T* temp = m_Ptr;
        m_Ptr = nullptr;
        return temp;
    }
    
    void Reset(T* ptr = nullptr)
    {
        delete m_Ptr;
        m_Ptr = ptr;
    }
    
    explicit operator bool() const { return m_Ptr != nullptr; }
};

// 工厂函数模板
template<typename T, typename... Args>
UniquePtr<T> MakeUnique(Args&&... args)
{
    return UniquePtr<T>(new T(std::forward<Args>(args)...));
}

class TestClass
{
private:
    std::string m_Name;
    int m_Value;
    
public:
    TestClass(const std::string& name, int value) : m_Name(name), m_Value(value)
    {
        std::cout << "Create " << m_Name << " with value " << m_Value << std::endl;
    }
    
    ~TestClass()
    {
        std::cout << "Destroy " << m_Name << std::endl;
    }
    
    void Print() const
    {
        std::cout << m_Name << ": " << m_Value << std::endl;
    }
};

int main()
{
    auto ptr1 = MakeUnique<TestClass>("Object1", 42);
    ptr1->Print();
    
    auto ptr2 = MakeUnique<int>(100);
    std::cout << "Value: " << *ptr2 << std::endl;
    
    return 0;
}

总结

  1. 模板基础:使用template<typename T>定义类型参数,实现泛型编程
  2. 函数模板:为不同类型生成相同逻辑的函数
  3. 类模板:创建可以处理不同类型的类
  4. 模板特化:为特定类型提供专门的实现
  5. 使用建议
    • 不要把模板写得太复杂
    • 好的模板应该让程序变得更简单
    • 模板在复杂情况下可能大大降低代码可读性
  6. 现代特性:C++11的可变参数模板、C++17的fold表达式、C++20的概念约束
updatedupdated2025-09-202025-09-20