在《C++ Template》中有一个辨识函数类型的模板技术,原文的例子貌似有些错误,这里做个对比验证,如有错误,请大家指出,原文的代码如下:
template<typename T> class CompoundT { public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 0, IsPtrMemT = 0 }; typedef T BaseT; typedef T BottomT; typedef CompoundT<void> ClassT; };
这是基本模板,接着需要定义一个基本模板的特化,用于识别函数类型:
template<typename T> class CompoundT<T()> { public: enum { IsPtrT = 0, IsRefT = 0, IsArrayT = 0, IsFuncT = 1, IsPtrMemT = 0 }; typedef T BaseT(); typedef T BottomT(); typedef CompoundT<void> ClassT; };
这个经过特化的类模板可以识别无参的函数类型,为了灵活使用,原文通过一个模板函数来完成具体的识别工作,如下:
template<typename T> void test(T){ cout<<typeid(T).name()<<endl; cout<<(CompoundT<T>::IsFuncT)<<endl; }
这个模板函数到底能不能工作呢,我们可以实地验证一下:
void fun(){} int main(){ test(fun); return 0; }
发现输出的结果如下:
typeid(T).name() : PFvvE
CompoundT<T>:: IsFuncT : 0
显然,识别的结果是错误的,问题是出在test的定义上,注意到test的参数列表时(T),也就是说采用了传值方式,而如果传递的是函数,会发生decay,即将函数名称decay为函数指针,所以 T 被推断成了函数指针类型,而不是函数类型,所以上面定义的特化版本无法与之匹配。现在将test重新定义如下:(将T改成T&)
template<typename T> void test(T&){ cout<<typeid(T).name()<<endl; cout<<(CompoundT<T>::IsFuncT)<<endl; }
再次执行相同的测试,结果如下:
typeid(T).name() : FvvE
CompoundT<T>:: IsFuncT : 1
可见,这样就可以正确识别函数类型了。此外,我们也可以看到模板函数与模板类结合使用的巨大优势,因为模板函数可以进行类型推断(类型演绎)。如果不使用函数模板,CompoundT的作用就大大下降了,因为不能写成CompoundT<fun>,因为fun不是一个类型,fun相当于类型的实例。为了更加具体地说明这一点,我们可以进行如下定义:
typedef void func();
这样就可以使用CompoundT<func>了,因为func现在是一个函数类型。
时间: 2024-10-08 06:04:34