首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 模板完整指南:從類模板、函數模板到特化、偏特化、成員模板與編譯模型

     編輯:關於C++

1. 類模板定義與實例化

語法基礎

template <class T, int Size = 100> // 類型參數 + 非類型參數(有默認值)
class Buffer {
    T data[Size];
    // ...
};

// 使用
Buffer<int> buf1;           // 使用默認 Size=100
Buffer<double, 256> buf2;   // 顯式指定非類型參數

模板參數規則

  • 類型參數:class T 或 typename T (等價)
  • 非類型參數:整型、枚舉、指針、引用、std::nullptr_t,必須是編譯期常量
  • 模板模板參數:template<class> class Container
  • 參數名在模板內作用域可見,不可重複,可與外部同名 (外部被遮蔽)

實例化機制

隱式實例化:使用模板類型時 (定義對象、sizeof、派生等) 自動觸發。

Buffer<int> buf; // 觸發 Buffer<int> 實例化
sizeof(Buffer<double>); // 觸發實例化以獲取大小
class Derived : Buffer<char> {}; // 觸發實例化

顯式實例化:template class Buffer<int>; 強制編譯器生成代碼,常用於庫的顯式導出。

2. 類模板成員函數

// 類內定義 (隱式 inline)
template <class T> class Stack {
    void push(const T& val) { elems.push_back(val); } // 內聯
    T pop() { T val = elems.back(); elems.pop_back(); return val; }
private:
    vector<T> elems;
};

// 類外定義 (需帶模板參數)
template <class T> 
void Stack<T>::push(const T& val) { elems.push_back(val); }

關鍵點:成員函數本身也是模板,僅在被調用時才實例化,未調用的成員不生成代碼 (支持 SFINAE)。

3. 類模板友元聲明

類型語法關係
非模板友元friend class Other; friend void func();所有實例共享同一友元
綁定友元模板template<class T> friend class Friend<T>;一對一:Buffer<int> 友元 Friend<int>
非綁定友元模板template<class U> friend class Friend;一對多:所有 Buffer 實例友元所有 Friend 實例
// 綁定友元需前置聲明
template <class T> class Friend;
template <class T> class Buffer {
    friend class Friend<T>; // 綁定
};
template <class T> class Friend { /* 可訪問 Buffer<T> 私有成員 */ };

4. 靜態成員與嵌套類型

template <class T> class Counter {
    static int count; // 每個實例化類型擁有獨立靜態成員
public:
    static int get() { return count++; }
    struct Nested { T value; }; // 嵌套類型也是模板
};

template <class T> int Counter<T>::count = 0; // 類外定義靜態成員

// 使用
Counter<int>::get(); // 0
Counter<int>::get(); // 1
Counter<double>::get(); // 0 (獨立計數)
Counter<int>::Nested n; // 嵌套類型需前綴實例化類名

5. 成員模板

class Widget {
public:
    // 構造函數模板:接受任何可轉換為 T 的類型
    template <class T> Widget(const T& val) : value(val) {}
    
    // 成員函數模板
    template <class T> void process(const T& param) { /* ... */ }
    
    // 嵌套類模板
    template <class T> struct Handler { void operator()(T&) {} };
private:
    int value;
};

// 使用
Widget w(3.14); // T=double
w.process("hello"); // T=const char*
Widget::Handler<int> h;

成員模板極大增強了類的泛化能力,標準庫智能指針構造函數即大量使用此技術。

6. 模板編譯模型

模型特點優點缺點
包含模型聲明+定義全在頭文件編譯器可見完整定義,支持內聯優化,最通用編譯依賴重,頭文件大,編譯慢
分離模型聲明在頭文件,定義在 .cpp,用 export隱藏實現,減少編譯依賴極少編譯器支持 (僅 EDG 前端),C++11 棄用
顯式實例化聲明頭文件聲明 extern template class Foo<int>;,.cpp 顯式實例化控制實例化位置,減少重複編碼,加快編譯需預知使用的類型,擴展性受限

現代最佳實踐:包含模型 (頭文件唯一) + 顯式實例化聲明 優化編譯速度。C++20 Modules 將徹底解決此問題。

7. 模板特化與偏特化

全特化

// 通用模板
template <class T>> class Serializer { /* 通用序列化 */ };

// 全特化:針對 string 優化
template <> class Serializer<string> {
public:
    static string to_json(const string& s) { return "\"" + escape(s) + "\""; }
};

// 成員函數全特化
template <> void Serializer<int>::serialize(int val) { /* 整數特化邏輯 */ }

偏特化 (僅類模板支持)

// 通用:兩個類型參數
template <class T1, class T2> class Pair { /* ... */ };

// 偏特化 1:第二個參數固定為 int
template <class T> class Pair<T, int> { /* 針對 int 優化 */ };

// 偏特化 2:指針類型
template <class T> class Pair<T*, T*> { /* 指針對專用邏輯 */ };

// 偏特化 3:引用類型
template <class T> class Pair<T&, T&> { /* 引用對專用 */ };

匹配規則:編譯器選擇最特化的版本。偏特化本身是模板,需提供完整成員定義。

8. 名字空間與模板

namespace MyLib {
    template <class T> class Vector { /* ... */ };
    template &<class T> T max(const T& a, const T& b) { return a

9. 經典案例:Stack 類模板完整實現

#include <vector> <stdexcept> <string>
using namespace std;

template <class T> class Stack {
    vector<T> elems;
public:
    void push(const T& elem) { elems.push_back(elem); }
    void push(T&& elem) { elems.push_back(std::move(elem)); }
    void pop() { 
        if (elems.empty()) throw out_of_range("Stack empty"); 
        elems.pop_back(); 
    }
    T top() const { 
        if (elems.empty()) throw out_of_range("Stack empty"); 
        return elems.back(); 
    }
    bool empty() const { return elems.empty(); }
    size_t size() const { return elems.size(); }
};

// 使用
int main() {
    Stack<int> intStack;
    intStack.push(7);
    cout << intStack.top() << endl; // 7
    
    Stack<string> stringStack;
    stringStack.push("hello");
    cout << stringStack.top() << endl; // hello
}

10. 函數模板基礎

// 基本語法
template <class T> T max(T a, T b) { return a < b ? b : a; }

// 類型推導
max(3, 5);       // T=int
max(3.14, 2.71); // T=double
max("a", "b");   // T=const char* (比較指針地址!需特化或重載)

// 顯式指定模板參數
max<double>(3, 4.5); // T=double, 隱式轉換

// 多參數模板
template <class T, class U> auto add(T a, U b) -> decltype(a+b) { return a+b; }

總結:模板元編程核心概念圖譜

模板參數
  ├─ 類型參數 (class/typename)
  ├─ 非類型參數 (整型/指針/引用/模板模板)
  └─ 默認參數 (右向左)

實例化機制
  ├─ 隱式 (使用時)
  ├─ 顯式 (template class Foo;)
  └─ 成員函數按需 (調用時)

特化層級
  ├─ 全特化 (template<> class Foo {})
  ├─ 偏特化 (類模板: template class Foo {})
  └─ 函數模板無偏特化 (用重載替代)

編譯模型
  ├─ 包含模型 (主流)
  ├─ 顯式實例化聲明 (優化編譯)
  └─ Modules (C++20 未來)

進階特性
  ├─ 成員模板 (構造/函數/嵌套類)
  ├─ 別名模板 (template using Vec = vector;)
  ├─ 變長模板 (template)
  └─ 概念/約束 (C++20 concepts)

模板是 C++ 泛型編程的基石,掌握其實例化機制、特化規則、編譯模型與進階特性,是編寫高效、通用、可維護 C++ 庫代碼的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved