In the process of template argument deduction, a C++ compiler attempts to instantiate signatures of a number of candidate overloaded functions to make sure that exactly one overloaded function is available as a perfect match for a given function call.
從上面的描述中我們可以看到,在對一個函數調用進行模板推導時,編譯器會嘗試推導所有的候選函數(重載函數,模板,但是普通函數的優先級要高),以確保得到一個最完美的匹配。
If an invalid argument or return type is formed during the instantiation of a function template, the instantiation is removed from the overload resolution set instead of causing a compilation error. As long as there is one and only one function to which the call can be dispatched, the compiler issues no errors.
也就是說在推導的過程中,如果出現了無效的模板參數,則會將該候選函數從重載決議集合中刪除,只要最終得到了一個 perfect match ,編譯就不會報錯。
如下代碼所示:
long multiply(int i, int j) { return i * j; }template <class T>typename T::multiplication_result multiply(T t1, T t2){ return t1 * t2;}int main(void){ multiply(4, 5);}
123456789101112123456789101112main 函數調用 multiply 會使編譯器會盡可能去匹配所有候選函數,雖然第一個 multiply 函數明顯是較優的匹配,但是為了得到一個最精確的匹配,編譯器依然會嘗試去匹配剩下的候選函數,此時就會去推導 第二個multiply函數,中間在參數推導的過程中出現了一個無效的類型 int::multiplication_result ,但是因為 SFINAE 原則并不會報錯。
std::enable_if<> 的實現
前面我們在介紹 std::enable_if 的時候提到,如果 condition 不滿足的話,會生成一個無效的類型,此處由于SFINAE 機制的存在,只要 call 存在一個匹配的話,就不會報錯(只是簡單的丟棄該函數)。
std::enable_if<>的實現機制如下代碼所示:
template<bool Cond, typename T = void> struct enable_if {};template<typename T> struct enable_if<true, T> { typedef T type; };
123123從上面的代碼可以看到
在 condition 為真的時候,由于偏特化機制,第二個結構體模板明顯是一個更好的匹配,所以 std::enable_if<>::type 就是有效的。
當 condition 為假的時候,只有第一個結構體模板能夠匹配,所以std::enable_if<>::type 是無效的,會被丟棄,編譯器會報錯:error: no type named ‘type’ in ‘struct std::enable_if<false, bool>。
Note: 下面是Visual Studio 2013的實現:
// TEMPLATE CLASS enable_iftemplate<bool _Test, class _Ty = void> struct enable_if { // type is undefined for assumed !_Test };template<class _Ty> struct enable_if<true, _Ty> { // type is _Ty for _Test typedef _Ty type; };
123456789101112123456789101112
std::enable_if<> 使用及使用
std::enable_if<> 的使用原型如下所示:
template <bool Cond, class T = void> struct enable_if;
11Cond, A compile-time constant of type boolT, A type.使用 enable_if 的時候,對參數有這兩方面的限制。
member type | definition |
---|
type | T (defined only if Cond is true) |
該例子來自于 這里:
// enable_if example: two ways of using enable_if#include <iostream>#include <type_traits>// 1. the return type (bool) is only valid if T is an integral type:template <class T>typename std::enable_if<std::is_integral<T>::value,bool>::type is_odd (T i) {return bool(i%2);}// 2. the second template argument is only valid if T is an integral type:template < class T, class = typename std::enable_if<std::is_integral<T>::value>::type>bool is_even (T i) {return !bool(i%2);}int main() { short int i = 1; // code does not compile if type of i is not integral std::cout << std::boolalpha; std::cout << "i is odd: " << is_odd(i) << std::endl; std::cout << "i is even: " << is_even(i) << std::endl; return 0;}
123456789101112131415161718192021222324
123456789101112131415161718192021222324頂