跳轉至內容

更多 C++ 習語/enable-if

來自 Wikibooks,開放書籍,開放世界

enable-if

[編輯 | 編輯原始碼]

允許基於型別的任意屬性進行函式過載

  • 顯式過載集管理

enable_if 模板族是一組工具,用於允許函式模板或類模板特化根據其模板引數的屬性將自身包含或排除在匹配函式或特化集之外。例如,可以定義僅針對由特徵類定義的任意型別集啟用的函式模板,並且因此僅與之匹配。enable_if 模板也可以應用於啟用類模板特化。enable_if 的應用在文獻中進行了詳細討論。[1] [2]

C++ 中模板函式過載的合理操作依賴於 SFINAE (替換失敗不是錯誤) 原則:[3] 如果在函式模板的例項化過程中形成了無效的引數或返回型別,則該例項化將從過載解析集移除,而不是導致編譯錯誤。以下示例[1] 說明了為什麼這一點很重要

int negate(int i) { return -i; }

template <class F>
typename F::result_type negate(const F& f) { return -f(); }

假設編譯器遇到呼叫 negate(1)。第一個定義顯然是更好的匹配,但編譯器仍然必須考慮(並例項化原型)這兩個定義才能找出這一點。用 F 作為 int 例項化第二個定義會導致

int::result_type negate(const int&);

其中返回型別無效。如果這是一個錯誤,新增一個無關的函式模板(從未被呼叫過)可能會破壞其他有效的程式碼。然而,由於 SFINAE 原則,上面的例子不是錯誤的。negate 的第二個定義只是從過載解析集移除。

enable_if 模板是用於控制建立 SFINAE 條件的工具。

解決方案和示例程式碼

[編輯 | 編輯原始碼]

enable_if 模板在語法上非常簡單。它們總是成對出現:其中一個為空,另一個具有一個type typedef,它轉發其第二個型別引數。空結構會導致無效型別,因為它不包含任何成員。當編譯時條件為假時,將選擇空的enable_if 模板。追加::type 會導致無效的例項化,編譯器會根據 SFINAE 原則將其丟棄。

template <bool, class T = void> 
struct enable_if 
{};

template <class T> 
struct enable_if<true, T> 
{ 
  typedef T type; 
};

以下是一個示例,展示瞭如何基於型別引數的任意屬性在編譯時選擇過載的模板函式。假設函式 T foo(T t) 是為所有型別定義的,只要 T 是算術型別。enable_if 模板可以作為返回值型別使用,如本例所示

template <class T>
typename enable_if<is_arithmetic<T>::value, T>::type 
foo(T t)
{
  // ...
  return t;
}

或者作為額外引數,如下所示

template <class T>
T foo(T, typename enable_if<is_arithmetic<T>::value >::type* = 0);

新增到 foo() 的額外引數被賦予預設值。由於 foo() 的呼叫者將忽略這個虛擬引數,因此它可以被賦予任何型別。特別是,我們可以允許它為 void *。考慮到這一點,我們可以簡單地省略 enable_if 的第二個模板引數,這意味著當 is_arithmetic<T> 為真時,enable_if<...>::type 表示式將評估為 void

是否將使能器編寫為引數或在返回型別中很大程度上取決於個人喜好,但對於某些函式,只有一種選擇是可行的

  • 運算子具有固定數量的引數,因此 enable_if 必須在返回值型別中使用。
  • 建構函式和解構函式沒有返回值型別;額外引數是唯一的選擇。

C++20 中的解決方案

[編輯 | 編輯原始碼]

從 C++20 開始,requires 語句可以用於實現與 enable_if 相同的功能。與 enable_if 一樣,如果使能器為 false,則會關閉過載。

template <class T>
T foo(T) requires(is_arithmetic<T>::value);

已知用途

[編輯 | 編輯原始碼]

Boost 庫、C++ STL 等。

[編輯 | 編輯原始碼]

參考資料

[編輯 | 編輯原始碼]
  1. a b Jaakko Järvi、Jeremiah Willcock、Howard Hinnant 和 Andrew Lumsdaine。基於型別的任意屬性的函式過載。C/C++ 使用者雜誌,21(6):25-32,2003 年 6 月。
  2. Jaakko Järvi、Jeremiah Willcock 和 Andrew Lumsdaine。概念控制的多型性。在 Frank Pfennig 和 Yannis Smaragdakis 編著的《生成式程式設計和元件工程》,LNCS 卷 2830,第 228-244 頁。施普林格出版社,2003 年 9 月。
  3. David Vandevoorde 和 Nicolai M. Josuttis。《C++ 模板:完整指南》。Addison-Wesley,2002 年。
[編輯 | 編輯原始碼]

Boost 庫 enable-if 文件

華夏公益教科書