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)