Loki中中有一个类似这样的类用以在编译阶段侦测两个类型是否具有可转换性:
template < typename T,typename U >
class TestType
... {
typedef char Small;
typedef struct...{char buf[2];} Big;
Small Test(T);
Big Test(...);
T MakeT();
public:
enum ...{exist = (sizeof(Small) == sizeof(Test(MakeT())))};
} ;
class Base ... {} ;
template < class T >
void doSomething(T & data)
... {
TestType<T,Base[100]>::exist;
}
int _tmain( int argc, _TCHAR * argv[])
... {
Base buf[100];
doSomething(buf);
return 0;
}
template
<
typename T,typename U
>
class TestType
... {
typedef char Small;
typedef struct...{char buf[2];} Big;
Small Test(T);
Big Test(...);
T MakeT();
public:
enum ...{exist = (sizeof(Small) == sizeof(Test(MakeT())))};
} ;
class TestType
... {
typedef char Small;
typedef struct...{char buf[2];} Big;
Small Test(T);
Big Test(...);
T MakeT();
public:
enum ...{exist = (sizeof(Small) == sizeof(Test(MakeT())))};
} ;
其中比较有新意的一点就是稻草人函数MakeT的使用,它解决了在T无法被构造的时候这个测试类无法使用的问题,但是却有一个小小的问题。那就是当T是数组的时候,函数是不允许回传数组的,所以这个类又无法使用了,可能作者未考虑到这种情况,毕竟很少有人变态到把完整的数组信息传来传去,但是我却在实际使用中遇到了。
template < typename T,typename U >
class TestType
... {
typedef char Small;
typedef struct...{char buf[2];} Big;
Small Test(T);
Big Test(...);
T MakeT();
public:
enum ...{exist = (sizeof(Small) == sizeof(Test(MakeT())))};
} ;
class Base ... {} ;
template < class T >
void doSomething(T & data)
... {
TestType<T,Base[100]>::exist;
}
int _tmain( int argc, _TCHAR * argv[])
... {
Base buf[100];
doSomething(buf);
return 0;
}
首先我使用了模板策略获得了函数传来的完整数组信息,然后为了确定数组是否是特定一个数组类型的时候,我想到了这个测试类,它报错了,编译器抱怨说函数回传了一个数组。
从我的认知范围里,我无法获得一个同样封装模式但可以解决这个问题的类,也许你想到这样:
template
<
typename T,typename U
>
class TestType
... {
typedef char Small;
typedef struct...{char buf[2];} Big;
Small Test(T);
Big Test(...);
T MakeT();
template <typename M>
GetRawType(M)
...{
return MakeT();
}
template <typename M>
GetRawType(M[])
...{
return M;
};
public:
enum ...{exist = (sizeof(Small) == sizeof(Test( GetRawType(T()) )))};
} ;
class TestType
... {
typedef char Small;
typedef struct...{char buf[2];} Big;
Small Test(T);
Big Test(...);
T MakeT();
template <typename M>
GetRawType(M)
...{
return MakeT();
}
template <typename M>
GetRawType(M[])
...{
return M;
};
public:
enum ...{exist = (sizeof(Small) == sizeof(Test( GetRawType(T()) )))};
} ;
但这成了鸡生蛋还是蛋生鸡的问题。
我尝试了很多办,包括类型选择和试图利用转掉const的策略转掉[],但是都没有成功,buf[100]已经在模板替换的时候被作为一个独立的类型了,我的类型选择必须得做成这样才可以运作:
template
<
typename T
>
struct IsArray
... {
typedef T Result;
enum ...{result = 2};
} ;
template < typename T >
struct IsArray < T[ 100 ] >
... {
typedef T Result;
enum ...{result = 1};
} ;
template < typename T >
void doSomething(T & buf)
... {
cout<<IsArray<T>::result<<endl;
}
int _tmain( int argc, _TCHAR * argv[])
... {
char buf[100];
doSomething(buf);
return 0;
}
struct IsArray
... {
typedef T Result;
enum ...{result = 2};
} ;
template < typename T >
struct IsArray < T[ 100 ] >
... {
typedef T Result;
enum ...{result = 1};
} ;
template < typename T >
void doSomething(T & buf)
... {
cout<<IsArray<T>::result<<endl;
}
int _tmain( int argc, _TCHAR * argv[])
... {
char buf[100];
doSomething(buf);
return 0;
}
注意我已经固化了这个数组T[100],这样的一个模板是没有任何实用价值的。
但是,到现在为止,我已有的知识无法让我封装出一个类库性质的东西,可是却可以得到这类问题的解法,当是真的要ASSERT某个特定类型是否为特定的具有完整信息的数组的时候,你可以这样:
template
<
typename T
>
struct IsArray
... {
enum ...{isarray = false};
} ;
template < typename T >
struct IsArray < T[ 100 ] >
... {
enum ...{isarray = true};
} ;
template < typename T >
void doSomething(T & buf)
... {
MyAssert(IsArray<T>::isarray);
}
int _tmain( int argc, _TCHAR * argv[])
... {
char buf[100];
doSomething(buf);
return 0;
}
struct IsArray
... {
enum ...{isarray = false};
} ;
template < typename T >
struct IsArray < T[ 100 ] >
... {
enum ...{isarray = true};
} ;
template < typename T >
void doSomething(T & buf)
... {
MyAssert(IsArray<T>::isarray);
}
int _tmain( int argc, _TCHAR * argv[])
... {
char buf[100];
doSomething(buf);
return 0;
}
注意这里的MyAssert是使用模板做成的编译期的assert功能。
这样验证特定数据是否是数组的问题得到了一个解法,虽然没有现成的类可用,但是毕竟你碰到这种情况的时候不多,而且我真的无法想到更好的办法了。