胡说八道

学而不思则罔,思而不学则殆

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::
假设我们有一个类型T,我们如何知道它是否是个函数?

 我们定义下面的一个类
 template<typename T> 
 class IsFunctionT 
 { 
 private: 
     typedef char One; 
     typedef struct { char a[2]; } Two; 
     template<typename U>
     static One test(...); 
     template<typename U>
     static Two test(U[]);//U (*)[1]); 
 public: 
     template<typename U>
     static bool IsFT()
     {
        return (sizeof(IsFunctionT<T>::test<T>(0)) == sizeof(One));
     }
 };

 template<typename T> 
 class IsFunctionT<T&>
 { 
 public: 
     template<typename U>
     static bool IsFT()
     {
       return false;
     }
 };

 template<> 
 class IsFunctionT<void>
 { 
 public: 
     template<typename U>
     static bool IsFT()
     {
       return false;
     }
 };

 template<> 
 class IsFunctionT<void const>
 { 
 public: 
     template<typename U>
     static bool IsFT()
     {
       return false;
     }
 };

 使用的时候
 typedef int ft();
 bool a=IsFunctionT<ft>::IsFT<ft>();

 让我们来仔细的看看上面的那个类
 1
 我们定义了两个私有的类型One和Two,分别是char和struct { char m[2];},这两个类型是为判断出我们采用了哪个函数服务的,不管在任何系统上这两个类型的size都应该是不同的.
 2
 我们还定义了3个静态的模板函数,其中两个是重载函数test,一个参数类型是...,另外的一个是U[],我们是通过显式的实例化这些模板函数.我们知道C++中是不能申明函数数组的(同样的还有void,void coonst和引用,所以采用了3个特例化来排除这几个类型).也就是说当我们实例化的时候传递的类型是函数类型,那么第二个test函数将匹配失败,编译器就会实例话第一个函数,这里用到了"substitution-failure-is-not-an-error" (SFINAE)原则.

 所以当我们采用函数类型作为参数调用IsFunctionT::IsFT的时候,函数内部调用sizeof(IsFunctionT::test<U>(0))的test版本就是test(...)的版本,所以得到的sizeof就等于sizeof(One).反之,如果是非函数类型,那么就是调用test(U[]),将0转化成需要的数据,这样得到的sizeof就不等于sizeof(One).

 我们就得到了判断类型是否是函数的方法.

 PS:<<C++ Templates>> is <<C++ Templates: The Complete Guide>>

posted on 2004-12-29 11:35  胡说八道  阅读(762)  评论(0)    收藏  举报