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; //则将value设为false
};
Paul Mensonides说它能够工作,我也觉得根据标准它也该能够工作,但事实是在我的VC7.0上编译器有一大堆抱怨。我试了其它各种方法,结果总是类似的编译错误将我挡住。我希望它在你的编译器上能够工作。
这里的原理是这样的,如果类型X有内嵌模板型别定义key_type,则has_template_key_type中的返回yes_type的那些成员函数总有一个能够与它匹配,而其它则不会被具现化(VC7.0仿佛总试图将其它的也具现化了,结果它总会抱怨说模板参数太少或太多)。
然而Paul Mensonides的这个解决方案还有个问题:如果那个内嵌的模板类的定义像如下这个样子:
template<int>
struct key_type{};
则将没有任何一个返回yes_type的重载版本能和它匹配,看看split类的定义吧,它的template template模板参数的形式是template<class[ ,class ,...]> class T,而上面的key_type的形式为template<int> class key_type,它们无法匹配,如果试图再加入一个能与其匹配的split偏特化版本:
template<template<int>class T,int T1> struct split<T<T1> >{...};
这也是不实际的。因为int和class可能有无穷多种组合。如果key_type再变成template<int,class> class key_type呢?如果...,总之,如你所见,以int作为模板参数的加入使事情有了无限多种可能。split将穷于应付。
结论(Conclusion)
对于最后我提出的问题,仿佛没有一个好的解决方案。所以只能放弃这种内嵌template的可能,假定情况是单纯的。对于后者,这种技术有教好的表现。