【zz】在C++中侦测内嵌类型的存在

www.ithao123.com/cpluspluslib/20071020/1671.html



一是利用函数重载

typedef char (&yes_type)[1]; // sizeof(yes_type)==1

typedef char (&no_type)[2]; // sizeof(no_type)==2

char (&)[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