SFINAE : Substitution Failure Is Not An Error template<class T,class> struct check_helper { typedef T type; }; template<class T,class =T> struct does_sometypedef_exists_1 { static const bool value=false; }; template<class T> struct does_sometypedef_exists_1<T, typename check_helper<T, typename T::key_type>::type> { static const bool value=true; template<class> struct split; // 缺省声明,因为不会被匹配所以不用定义 // 以下是偏特化 template< template<class> class T, class T1 > // T为模板 struct split< T<T1> > { struct type { }; }; template< template<class, class> class T, class T1, class T2 > struct split< T<T1, T2> > { struct type { }; }; // etc. :(,后面有支持更多模板参数的版本,从略 template<class T> class has_template_key_type { private: template<class U> static yes_type check( typename split< typename U::template key_type<null_t> >::type
No. 1
Both of the following compiles error. (g++-3.4.4)
> template<unsigned> struct sample { };
>
> struct X {
> X(int, int); // no default ctor
> };
>
> template<class T> void check( sample<sizeof(new T)> ) { }
> template<class T> void check( int ) { }
>
> int main() {
> check<X>(0);
> return 0;
> }
> template<unsigned> struct sample { };
>
> struct X {
> X(int, int); // no default ctor
> };
>
> template<class T> void check( sample<sizeof(new T)> ) { }
> template<class T> void check(…) { }
^^^^^
>
> int main() {
> check<X>(0);
> return 0;
> }
an explanation from http://topic.csdn.net/t/20031120/22/2478518.html
>to plainsong:
这个例子里发生的事情比你想象的要微妙的多。
>to plainsong && firingme(木头)
如果要要了解事情的全部,可以去
comp.std.c++查找如下标题的帖子:
14.8.2 Clarification?
<其次,按照我的理解在这里描述一下这个例子:
》template<class T> void check( sample<sizeof(new T)> ) { }
———#1
》为何
》template<class T> void check( int ) { }
———#2
》时可以编译通过? // 实际上我用g++-3.4.4未编译通过
当调用check<X>(0)时,首先进行模板参数推导:
#1:T = X, ——————————◆◆◆
因为 sizeof(new T)虽然是无效表达式,
但不是无效类型,所以这里不发生SFINAE。
也就是模板参数推导成功。
特殊化版本为:
void check<X>(sample<sizeof(new X)>);
————–#3
#2: T = X
模板参数推导成功。
void check<X>(int);
—————#4
#3和#4之间比较之后,#4被选中,然后,导致
void check<X>(int)的声明和定义产生
隐式实例化。
这里关键的一点是
#3没有被隐式实例化,
其中
#3的定义没有被隐式实例化
是很明显的,
而让人产生争议的是
#3的声明为什么没有被隐式实例化
(如果隐式实例化声明,将导致sizeof<new T>出现错误!!!
关于这一点,是comp.std.c++上那一贴里的争论焦点)
————————-★★★★★
最后,一切正常,
check<X>(0)调用#4, 编译通过。
》而
》template<class T> void check(…) { }
———–#5
》时就不能通过了?
当调用check<X>(0)时,首先进行模板参数推导:
#1 :T = X
分析如前面所描述——–>见◆◆◆
void check<X>(sample<sizeof(new X)>);
————–#5
#5 : T = X
模板参数推导成功:
void check<X>(…)
————–#6
#5,#6重载解析后, #5被选中,
导致#5这个模板特殊化版本产生一个
隐式实例化(包含声明实例化和定义实例化)
这一实例化过程将导致
sizeof(new X) 出现错误, 因为X没有无参数构造函数版本。
结果是出现编译错误,提示的是
sizeof(new X) 出错,在实例化过程中。
★★★★★处发生的事情让人产生些争论,这也是
firingme(木头) 提的最后让david退却的地方。
按照David的说法,★★★★★处发生了一部分声明的实例化,
这个实例化被称之为
"partial instantiation"。
这个例子虽然不直接应用SFINAE,因为每次它都成功了,但却很
清楚的说明了我们在理解SFINAE时需要理解的很多东西。
而这个例子:
#include <iostream>
using namespace std;
/
#include <iterator>
using std::distance;
/
int distance(int a, int b)
{ return a - b; }
int main()
{
int a =10;
int b = 1;
cout << distance(a, b);
}
则是真实的说明了现实中需要SFINAE:
不然这个代码将不能
编译通过,
—–这绝对是不能容忍的
No. 2
The following will deduce OK. see http://hi.baidu.com/j_Ffo/blog/item/9ba80ed7107464dea144df88.html
No. 3
The following has problems again.
);
template<class U>
static yes_type check(
typename split<
typename U::template key_type<null_t, null_t> >::type
);
// etc. :( 后面有支持更多模板参数的版本,从略
template<class U> static no_type check(…);
public:
static const bool value
= sizeof(check<T>(0)) == sizeof(yes_type);
};
template<class T, bool V = has_template_key_type<T>::value>
class has_key_type
{
private:
template<class U> static yes_type check(typename U::key_type);
template<class U> static no_type check(…);
public:
static const bool value
= sizeof(check<T>(0)) == sizeof(yes_type);
};
template<class T> struct has_key_type<T, true>
{
static const bool value = false;
};