compare 什么的大家都很熟了:
int compare(int, int) {...}
想写通用一些? 加强版:
template<typename T>
int compare(T const &, T const &) {...}
类型泛化? 默认类型参数? … 最终会出现类似这样的版本: (涉及到函数到底要重载还是特化, 以及函数模板不支持默认参数等问题, 此处暂不讨论该问题)
template<typename T0, typename T1>
class CompareHolder
{
public:
static int compare(T0 const &, T1 const &) {...}
};
template<typename T0, typename T1>
int compare(T0 const &v0, T1 const &v1)
{
return CompareHolder<T0, T1>::compare(v0, v1);
}
好了, 学院派的东西扯完了, 开始实用派, 首先自然是自定义类型的模板特化:
class YourType {...}
template<>
class CompareHolder<YourType, YourType>
{
public:
static int compare(YourType const &, YourType const &) {...}
};
于是扯出了本文的重点: 当 YourType 有一个子类, 并且你希望不写任何代码, 让这个子类使用父类的特化版本, 应该如何做呢?
咋看一下很简单对吧? 写一写就知道个中蛋疼之处了, 有兴趣请先自行尝试体会一下
直接上最终的解决方案:
首先需要一个东西, 能够在编译期判断某个类是否是另一个类的子类
template<typename TChild, typename TBase>
class ClassIsTypeOf
{
private:
class _Yes {};
class _No {char dummy[16];};
static _Yes _test(TBase *);
static _No _test(...);
public:
enum {value = (sizeof(_test((TChild *)0)) == sizeof(_Yes))};
};
#define CLASS_IS_TYPE_OF(TChild, TBase) ClassIsTypeOf<TChild, TBase>::value
如果 TChild 是 TBase 的子类, 则 _test 会调用到 "_Yes _test(TBase *)" 的版本, 最终导致 value 为 1, 而这些都是可以在编译期决定
然后需要一个东西, 能够把 0 和 1 变成 "可推导" 以及 "不可推导" 的东西 (STL 中有类似的东西: enable_if)
template<typename T, int condition>
class EnableIf
{
};
template
class EnableIf<T, 1>
{
public:
typedef void Type;
};
有了这货, 由于 EnableIf<DummyType, 0>::Type 没有定义, 如果引用的话, 编译不通过, 可以造成依赖它的东西无法正常推导
接下来, 我们要改造一下 compare, 让它多几个空参数, 使得上面的 EnableIf 能排上用场
template<typename T0, typename T1, typename Fix0 = void, typename Fix1 = void>
class CompareHolder
{
public:
static int compare(T0 const &, T1 const &) {...}
};
还有用于加载它的 loader:
template<typename T0, typename T1>
int compare(T0 const &v0, T1 const &v1)
{
return CompareHolder<T0, T1>::compare(v0, v1);
}
最后, 把浑身解数都屎出来, 开始我们又臭又长的特化版本: (设名字叫 YourType0 和 YourType1)
template<typename T0, typename T1>
class CompareHolder<T0, T1
, typename EnableIf<YourType0, CLASS_IS_TYPE_OF(T0, YourType0)>::Type
, typename EnableIf<YourType1, CLASS_IS_TYPE_OF(T1, YourType1)>::Type
>
{
public:
static int compare(T0 const &, T1 const &) {...}
};
晕了没? 晕了就对了
这里特化的不是 T0, T1, 而是 Fix0, Fix1
当 T0/T1 不是 YourType0/YourType1 的子类时, EnableIf<YourType0, CLASS_IS_TYPE_OF(T0, YourType0)>::Type
最终的推导结果是未定义, 导致特化版本推导失败, 编译器就会自动使用非特化版本
反之, 虽然 EnableIf 最终的推导结果与非特化版本同样是 void, 但是由于其整体是作为一个 typename, 编译器会将其视为一个 type, 从而它会被视为一个推导成功的特化版本, 最终调用该特化的版本
STL 中应该有类似的处理方式, 至少有 std::enable_if, 具体的没细看, STL 什么的我就只用用 vector/map 连 iostream 都不用你以为我会乱说?
另外, 其实可以提供一个全局的 operator <, >, == 等比较函数, 但是某些情况下还是不方便, 而通过模板特化可以减小对原有代码的影响
C++ 果然很难啊… 以后再也不敢说精通 C++ 了
over
转载请注明来自: http://zsaber.com/blog/p/16
既然都来了, 有啥想法顺便留个言呗? (无奈小广告太多, 需审核, 见谅)