6.3 Disable Templates with enable_if<>
6.3 使用enable_if<>來禁用模板
Since C++11, the C++ standard library provides a helper template std::enable_if<> to ignore function templates under certain compile-time conditions.
自從C++11開始,C++標准庫提供了一個std::enable_if<>輔助模板,以便在某些編譯條件下忽略函數模板。
For example, if a function template foo<>() is defined as follows:
例如,函數模板foo<>的定義如下:
template<typename T> typename std::enable_if<(sizeof(T) > 4)>::type foo() { }
this definition of foo<>() is ignored if sizeof(T) > 4 yields false. if sizeof(T) > 4 yields true, the function template instance expands to
foo<>函數模板的定義在sizeof(T)>4不成立時被忽略掉。如果sizeof(T)>4,則函數模板的實例會展開成:
void foo()
{ }
That is, std::enable_if<> is a type trait that evaluates a given compile-time expression passed as its (first) template argument and behaves as follows:
也就是說std::enable_if<>是一種類型萃取,它會將其(第1個)模板實參作為編譯期表達式進行評估,其行為如下:
• If the expression yields true, its type member type yields a type:
如果表達式結果為true,它的type類型成員會返回一個類型:
– The type is void if no second template argument is passed.
如果沒有第2個模板參數,返回類型為void。
– Otherwise, the type is the second template argument type.
否則,返回類型為其第2個模板參數的類型。
• If the expression yields false, the member type is not defined. Due to a template feature called SFINAE (substitution failure is not an error), which is introduced later (see Section 8.4 on page 129), this has the effect that the function template with the enable_if expression is ignored.
如果表達式結果為false,則其成員類型是未定義的。根據模板一個叫做SFINAE(替換失敗不是錯誤)的規則,將導致包含std::enable_if表達式的函數模板被忽略掉。關於SFINAE將在后面的第129頁8.4節介紹。
As for all type traits yielding a type since C++14, there is a corresponding alias template std::enable_if_t<>, which allows you to skip typename and ::type (see Section 2.8 on page 40 for details). Thus, since C++14 you can write
由於從C++14開始,所有的類型萃取(type traits)都會返回一個類型。可以使用一個與之對應的別名模板std::enable_if_t<>,這樣就可以省略掉typename和::type(詳見第40頁的2.8節)。因此,從C++14開始,你可以編寫
template<typename T> std::enable_if_t<(sizeof(T) > 4)> foo() { }
If a second argument is passed to enable_if<> or enable_if_t<>:
假如給std::enable_if<>或std::enable_if_t<>傳入第2個模板參數:
template<typename T> std::enable_if_t<(sizeof(T) > 4), T> foo() { return T(); }
the enable_if construct expands to this second argument if the expression yields true. So, if MyType is the concrete type passed or deduced as T, whose size is larger than 4, the effect is如果sizeof(T)>4表達式結果為true時,enable_if<>被會擴展成其第2個模板參數。因此,如果MyType是個具體類型或通過T推導的類型,且其size大於4時,那么等價於:
MyType foo();
Note that having the enable_if expression in the middle of a declaration is pretty clumsy. For this reason, the common way to use std::enable_if<> is to use an additional function template argument with a default value:
但是將enable_if表達式放在聲明的中間是一個笨拙的做法。因此,使用std::enable_if<>更常見的做法是通常是使用一個額外、帶有默認值的模板參數:
template<typename T, typename = std::enable_if_t<(sizeof(T) > 4)>> void foo() { }
which expands to
如果sizeof(T)>4時,它將會被展開為
template<typename T, typename = void> void foo() { }
if sizeof(T) > 4.
If that is still too clumsy, and you want to make the requirement/constraint more explicit, you can define your own name for it using an alias template:
如果這依然不夠明智,並且希望需求或約束更加明顯,你可以使用別名模板來自定義的一個名稱。
template<typename T> using EnableIfSizeGreater4 = std::enable_if_t<(sizeof(T) > 4)>; template<typename T, typename = EnableIfSizeGreater4<T>> void foo() { }
See Section 20.3 on page 469 for a discussion of how std::enable_if is implemented.
關於std::enable_if實現的更多討論,請參閱第469頁的20.3節。