www.ithao123.com/cpluspluslib/20071020/1671.html
一是利用函数重载:
typedef char (&yes_type)[1]; // sizeof(yes_type)==1
typedef char (&no_type)[2]; // sizeof(no_type)==2char (&)[1]表示对char[1]数组的引用,注意围绕&符号的一对圆括号,它们是必要的,如果没有将会导致编译错误,正如char [1]将被解析为char的数组,char& [1]将被解析为引用的数组,而后者是非法的。将&用圆括号包围则改变了运算符的结合优先序,这将被解析为对char[1]数组的引用。
template<class T>
struct does_sometypedef_exists
{
template<class U>
static yes_type check(U, typename U::key_type =0); // #1
static no_type check(…);
static T t; // 声明
static const bool value = sizeof(check(t))==sizeof(yes_type);
};或改进如下:
template<class T>
struct does_sometypedef_exists
{
template<class U>
static yes_type check(typename U::key_type );
template<class U>
static no_type check(…);
static const bool value = sizeof(check<T>(0))==sizeof(yes_type);
};or: (compiled OK in gcc-3.4.4)
template<class T>
struct does_sometypedef_exists
{
template<class U>
static yes_type check(typename U::key_type );
template<class U>
static yes_type check(typename U::template key_type<null_t> );
template<class U>
static no_type check(…);
static const bool value = sizeof(check<T>(0))==sizeof(yes_type);
};
注意,#1处,和=之间的空格是必要的,否则编译器会将它解析为operator=操作符。
在我的VC7.0环境下,以下测试是成功的:
struct A{};
struct B
{
typedef int key_type;
};
int main()
{
std::cout << does_sometypedef_exists<A>::value<<’ ‘ // 0
<< does_sometypedef_exists<B>::value<<’ ‘ // 1
<< std::endl;
};
但这里有一个十分怪异的问题(在我的VC7.0环境下存在),假设我们增加一个新类:
struct C
{
template<class T>
struct key_type{}; // 请注意这是个模板类
};
第二种实现是利用模板偏特化及默认模板参数的规则:
template<class T,class>
struct check_helper
{
typedef T type;
};
template<class T,class =T>
struct does_sometypedef_exists_1
{
static const bool value=false;
};
template<class T>
struct does_sometypedef_exists_1<T,
typename check_helper<T, typename T::key_type>::type>
{
static const bool value=true;
};
测试(Test)
现在对我们的两个实现版本测试一下吧,假设有一下几个类:
// 没有key_type
struct A{};
// typedef
struct B{typedef int key_type;};
// key_type为成员函数
struct C{void key_type(void){}};
// key_type为静态常量数据成员
struct D{static const bool key_type=false;};
// 定义,D里面的是声明
const bool D::key_type;
// key_type为模板类
struct E{
template<class>
struct key_type{};
};
template<class T>
struct does_typedef_exists
{
typedef does_sometypedef_exists<T> impl_type;
static const bool value = impl_type::value;
};
int main()
{
std::cout << does_typedef_exists<A>::value<<’ ‘
<< does_typedef_exists<B>::value<<’ ‘
<< does_typedef_exists<C>::value<<’ ‘
<< does_typedef_exists<D>::value<<’ ‘
<< does_typedef_exists<E>::value<<’ ‘
<< std::endl;
return 0;
};在VC7.1编译平台上:
如果使用第一种实现,这将输出:0 1 0 0 1
如果使用第二种实现,这将输出:0 1 0 0 0
第三种实现(VC7.1、VC8.0和gcc-3.x.x、gcc-4.x.x中编译都通不过)
template<class> struct split; // 缺省声明,因为不会被匹配所以不用定义
// 以下是偏特化
template< template<class> class T, class T1 > // T为模板
struct split< T<T1> > {
struct type { };
};
template< template<class, class> class T, class T1, class T2 >
struct split< T<T1, T2> > {
struct type { };
};
// etc. :(,后面有支持更多模板参数的版本,从略
template<class T> class has_template_key_type
{
private:
template<class U>
static yes_type check(
typename split<
typename U::template key_type<null_t> >::type
);
template<class U>
static yes_type check(
typename split<
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;
};
来自:http://blog.csdn.net/pongba/archive/2004/08/24/82783.aspx