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)