对于Policy的兼容性,也就是转换的策略,我们来考虑这段代码:
template
<
class T,
template < class > class CheckPolicy
>
class SmartPtr : public CheckPolicy < T >
... {
template
<
class T1,
template <class> class CP1
>
SmartPtr(const SmartPtr<T1,CP1>& other)
:pointee_(other.pointee_),CheckPolicy<T>(other)
...{
}
} ;
<
class T,
template < class > class CheckPolicy
>
class SmartPtr : public CheckPolicy < T >
... {
template
<
class T1,
template <class> class CP1
>
SmartPtr(const SmartPtr<T1,CP1>& other)
:pointee_(other.pointee_),CheckPolicy<T>(other)
...{
}
} ;
其实这就是一个类的声明:
#define
OUT_TEMPLATE(TNAME,CNAME)
template
<
class ##TNAME,
template < class > class ##CNAME
>
#define IN_TEMPLATE(TNAME,CNAME)
template
<
class ##TNAME,
template < class > ##CNAME
>
OUT_TEMPLATE(T,CheckPolicy)
class SmartPtr : public CheckPolicy < T >
... {
IN_TEMPLATE(T1,CP1)
SmartPtr(const SmartPtr<T1,CP1>& other)
:pointee_(other.pointee_),CheckPolicy<T>(other)
...{
}
} ;
template
<
class ##TNAME,
template < class > class ##CNAME
>
#define IN_TEMPLATE(TNAME,CNAME)
template
<
class ##TNAME,
template < class > ##CNAME
>
OUT_TEMPLATE(T,CheckPolicy)
class SmartPtr : public CheckPolicy < T >
... {
IN_TEMPLATE(T1,CP1)
SmartPtr(const SmartPtr<T1,CP1>& other)
:pointee_(other.pointee_),CheckPolicy<T>(other)
...{
}
} ;
通过SmartPtr定义的一个拷贝构造函数,我们可以这样做:
SmartPtr ptr;
SmartPtrEx ptrx;
ptr = SmartPtr(ptrx);
SmartPtrEx ptrx;
ptr = SmartPtr(ptrx);
是的,你看到了类型转换,这就是Policies的兼容性。
我们来讨论它的可行性:
对于SmartPtr<WidgetEx,NoChecking>到SmartPtr<Widget,Nochecking>,这没有问题,WidgetEx当然可以转换成基类Widget,而SmartPtr<WidgetEx,NoChecking>继承于NoChecking,这个转换也没有一点问题。
当你想把SmartPtr<WidgetEx,Nochecking>转换为一个SmartPtr<Widget,EnforceNotNull>的时候,我们需要更多前提。按照上边的思想,如果Nochecking可以转换为EnforceNotNull,这个可以成立。按照这个思想,如果EnforceNotNull存在可以接受NoChecking的构造函数,这个也可以成立。如果二者都没有,那就无法转换。
如Andrei所说:当你进行policies转换时,两边都有弹性。左手边你可以提供构造函数,右手边你可以做转换操作。
这里的左手右手如此定义:
ptr
=
SmartPtr(ptrx);
ps
通过这个实例应该对template class和template function有更好的理解和区分,也应该对偏特化里的函数偏特化与类偏特化的限制有更好的理解。