SFINAE:即Substitution Failure Is Not an Error!可以理解為匹配失敗不是錯誤,更嚴格的說應該是參數匹配失敗不是一個編譯時錯誤。
C++函數匹配的順序遵循的原則是按照以下順序
1.尋找參數的完美匹配函數,找到則使用
2.尋找模板函數,若實例化後的函數能夠匹配則使用
3.通過默認類型轉換後的參數去匹配,找到則使用
4.匹配失敗,提示函數匹配錯誤
下面通過實現is_base_of來說明SFINAE的一般用法,來自於
http://stackoverflow.com/questions/2910979/how-does-is-base-of-work
1.定義
1 namespace blog { 2 template <class D, class B> 3 struct ConversionHelper 4 { 5 struct Host 6 { 7 operator B() const; 8 operator D(); 9 }; 10 typedef char(&yes)[1]; 11 typedef char(&no)[2]; 12 template <typename T> 13 static yes Test(D, T); 14 static no Test(B, int); 15 }; 16 17 template <class D, class B> 18 struct Conversion 19 { 20 typedef ConversionHelper<D, B> H; 21
22 typedef typename H::Host Host; 23 enum { exists = sizeof(typename H::yes) == sizeof(H::Test(Host(), int())) }; 24 enum { exists2Way = exists && Conversion<B, DD>::exists }; 25 enum { sameType = false }; 26 }; 27 28 template <class D> 29 struct Conversion<D, D> 30 { 31 enum { exists = 1, exists2Way = 1, sameType = 1 }; 32 }; 33 34 template <class D> 35 struct Conversion<void, D> 36 { 37 enum { exists = 1, exists2Way = 0, sameType = 0 }; 38 }; 39 40 template <class D> 41 struct Conversion<D, void> 42 { 43 enum { exists = 1, exists2Way = 0, sameType = 0 }; 44 }; 45 46 template <> 47 struct Conversion<void, void> 48 { 49 public: 50 enum { exists = 1, exists2Way = 1, sameType = 1 }; 51 }; 52 53 template<typename B, typename D> 54 struct is_base_of { 55 enum { 56 value = (me::Conversion<const D*, const B*>::exists && !me::Conversion<const B*, const void>::sameType) 57 }; 58 }; 59 }
1 template<typename B,typename D> 2 struct is_base_of { 3 enum { 4 value = (Conversion<const D*, const B*>::exists && !Conversion<const B*, const void>::sameType) 5 }; 6 };
2.使用
1 struct A{}; 2 struct B{}; 3 struct C : public B 4 { 5 static_assert(blog::is_base_of<C, B>::value, "B is not the base of C"); 6 //static_assert(std::is_base_of<C, B>::value, "B is not the base of C"); 7 };
在上面代碼中,由於std::is_base_of<C,B>在struct C結構體中,C還沒有定義完整,因此會出錯。
而blog::is_base_of<C,B>使用的是指針轉換,當轉換存在時,ConversionHelper::Test(D,T)