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

C++ 模板進階:局部特化、成員特化、typename/template 消歧與 Traits 技法

     編輯:C++ 入門

前言

本文整理自《C++必知必會》條款 47-54,系統講解模板特化機制、依賴名稱消歧、成員模板、類型萃取等進階主題,是模板元編程的基石。

條款 47:模板局部特化

函數模板不能局部特化,只能重載

template void f(T);      // 主模板
template void f(T*);     // 重載,非特化

類模板支援局部特化

template class Heap;           // 主模板
template class Heap { ... }; // 局部特化:所有指釖類型
template<> class Heap { ... };  // 完全特化:const char*

優先級規則:完全特化 > 局部特化 > 主模板。實參為 const char* 時匹配完全特化;其他指釖匹配局部特化。

局部特化參數列表可異於主模板

template class Heap { ... }; // 針對固定大小數組

條款 48:類模板成員特化

特化整個類 vs 特化單個成員函數:

// 主模板
template class Heap {
public: void push(const T& val);
};

// 成員函數完全特化
template<> void Heap::push(const char* const & pval) { ... }

關鍵規則:若存在局部特化 Heap,則 Heap::push 必須匹配局部特化中的簽名(參數為 T* 而非 const T&)。

條款 49:用 typename 消除嵌套類型歧義

在模板中,編譯器無法判斷 T::iterator 是類型還是靜態成員,需加 typename:

template
void print(const T& c) {
    typename T::const_iterator it = c.begin(); // 告訴編譯器這是類型
    ...
}

條款 50:成員模板

成員本身是模板,常用於構造函數接受迭代器範圍:

template
class Slist {
public:
    template
    Slist(In begin, In end);  // 成員模板
};

template
template
Slist::Slist(In begin, In end) : head_(0) {
    while (begin != end) push_front(*begin++);
    reverse();
}

條款 51:用 template 關鍵字消除模板名稱歧義

當依賴名稱是模板時,需在 :: 後加 template:

template>
class SList {
    typedef typename A::template rebind::other NodeAlloc; // 正確
    // typedef A::rebind::other NodeAlloc; // 錯誤:編譯器以為 rebind 是靜態成員
};

typename 告訴編譯器「整個表達式是類型」,template 告訴編譯器「rebind 是模板」。

條款 52:針對類型信息的特化(編譯期類型判斷)

template struct IsInt { enum { result = false }; };
template<> struct IsInt { enum { result = true }; };

template
void aFunc(X& arg) {
    if (IsInt::result) { /* X 是 int */ }
}

這是 Traits 技法 的雛形:透過特化提取類型屬性。

條款 53:嵌入式類型信息

容器通過嵌套 typedef 暴露類型信息:

template
class Seq {
public:
    typedef T Elem;      // 元素類型
    typedef T Temp;      // 臨時對象類型
    size_t size() const;
};

typedef Seq Strings;
Strings::Elem aString;  // 編譯期獲取元素類型

條款 54:Traits 類

將類型相關操作封裝到獨立 Traits 類,實現「非侵入式」類型擴展:

template struct CharTraits;  // 主模板
template<> struct CharTraits {     // 完全特化
    static void assign(char&, char);
    static bool eq(char, char);
    // ...
};

標準庫 std::char_traits、std::iterator_traits、std::numeric_limits 皆屬此類。

總結對照表

技術關鍵字用途
類模板完全特化template<>特定類型完全不同實現
類模板局部特化template<T> Class<T*>一類類型共享實現
成員函數特化template<> void Class<T>::f()單一函數特化
依賴類型聲明typename嵌套類型名稱
依賴模板名稱template嵌套模板名稱
Traits特化結構體類型屬性萃取

實戰建議

  • 優先使用 using 別名模板(C++11)替代嵌套 typedef
  • 善用 std::void_t (C++17) 實現 SFINAE 檢測
  • 掌握 std::conditional, std::enable_if 等標準 Traits 工具
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved