questions about SFINAE

SFINAE : Substitution Failure Is Not An Error

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

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;

};

No. 3

The following has problems again.

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

);

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;

};