1、编译器assert
#pragma warning(disable:4101)
//
///使用数组,无法传入额外参数
#define STATIC_ASSERT1(express) {char unnamed[(express) ? 1 : 0];} // 使用大括号是为了保证作用域,防止名字冲突
//
//使用类构造函数,同样无法传入额外参数方便上层调用者知道是在哪里
template<bool>
class CTestAssert2;
template<>
class CTestAssert2<true>{};
#define STATIC_ASSERT2(express) {CTestAssert2<express>();}
//
// 使用类构造函数参数,可以让上层传入字符串
template<bool>
class CTestAssert3;
// 为true时任意类型都能转换
template<>
class CTestAssert3<true>
{
public:
CTestAssert3(...);
};
// 为false时,使用编译器自动生成的默认构造函数,甚至没有构造函数
template<>
class CTestAssert3<false>
{
};
#define STATIC_ASSERT3(express,usermsg) \
{\
class Error##usermsg{};\
Error##usermsg tmp;\
sizeof(CTestAssert3<express>(tmp));\
}
void CTestThchniques::TestCompileAssert()
{
STATIC_ASSERT1(1);
//STATIC_ASSERT1(0);
STATIC_ASSERT2(1);
//STATIC_ASSERT2(0);
STATIC_ASSERT3(1, a);
//STATIC_ASSERT3(0, displayme);
}
2、常整数映射为类型,方便实现函数的重载
// 将整数映射成为一个类型
template<int v>
struct Int2Type
{
enum{value = v};
};
//
class CIsClone
{
public:
CIsClone* clone(){return NULL;}
CIsClone(){};
private:
CIsClone(const CIsClone& rhs);
};
class CNotClone
{
public:
CNotClone(const CNotClone& rhs){}
CNotClone(){}
};
template<typename T, bool bSupportclone>
class CTestInt2Type_Old
{
public:
void DoSomeThing()
{
T* pt = new T;
if (bSupportclone)
{
T* pNewObj = pt->clone();
}
else
{
T* pNewObj = new T(*pt);
}
}
};
template<typename T, bool bSupportclone>
class CTestInt2Type
{
public:
void DoSomeThing()
{
DoSomeThing(Int2Type<bSupportclone>());
}
private:
void DoSomeThing(Int2Type<true> a)
{
T* pt = new T;
T* pNewObj = pt->clone();
}
void DoSomeThing(Int2Type<false> b)
{
T* pt = new T;
T* pNewObj = new T(*pt);
}
};
void CTestThchniques::TestInt2TypeFun()
{
// 被注释代码是无法编译通过的
//CTestInt2Type_Old<CIsClone, true> aa;
//aa.DoSomeThing();
//CTestInt2Type_Old<CNotClone, false> bb;
//bb.DoSomeThing();
CTestInt2Type<CIsClone, true> aa;
aa.DoSomeThing();
CTestInt2Type<CNotClone, false> bb;
bb.DoSomeThing();
}
3、型别对型别的映射
// 通过模板函数重载,解决无法偏特化问题
// 但是重载会导致参数传入的开销,可以通过Type2Type解决
template<typename T>
struct Type2Type
{
typedef T OriginalType;
};
//
// 这是一个重量级的参数,需要构造,拷贝,析构,
// 而它的作用只是根据类型来区分不同的函数重载
template<typename U, typename T>
T* Create_Old(const U& arg, const T& type)
{
return new T(arg);
}
template<typename U>
bool* Create_Old(const U& arg, const bool& type)
{
return new bool(arg);
}
// 这是一个轻量级的参数。但是它也足够满足区分不同函数重载的需求了
template<typename U, typename T>
T* Create(const U& arg, Type2Type<T> type)
{
return new T(arg);
}
template<typename U>
bool* Create(const U& arg, Type2Type<bool> type)
{
return new bool(arg);
}
void CTestThchniques::TestType2TypeFun()
{
bool* bc = new bool(true);
string* stra = Create_Old("abc", string());
bool* ba = Create_Old(true, bool());
string* strb = Create("abc", Type2Type<string>());
bool* bb = Create(false, Type2Type<bool>());
}
4、型别选择,根据参数选择适当的类型
// 根据flag控制Result类型,适合bool类型区控制类型
template<bool flag, typename T, typename U>
struct Select
{
typedef T Result;
};
template<typename T, typename U>
struct Select<false, T, U>
{
typedef U Result;
};
//
template<typename T, bool bIsClone>
struct TestTypeSelect
{
typedef typename Select<bIsClone, T* ,T>::Result ValueType;
ValueType aa;
};
5、编译器检测可转换型和可继承性,运行期检测使用dynamic_cast
template<typename T, typename U>
class CConversion
{
typedef char Small;
class Big
{
char dymmy[2];
};
static Small Test(U);
static Big Test(...);
static T MakeT();
public:
// 如果MakeT的类型为T能够转换为U,就会返回sizeof(Small)了,这样值就是1,不能转换就会返回Big了
// 依赖于编译器的函数重载
enum
{
TCanConversionU = sizeof(Test(MakeT())) == sizeof(Small), // T是否能转换为U
CanConversion2Way = TCanConversionU && CConversion<U, T>::TCanConversionU,// 是否能相互转换
};
enum
{
SameType = false
};
};
template<typename T>
class CConversion<T, T>
{
public:
enum
{
TCanConversionU = 1,
CanConversion2Way = 1,
}
enum
{
SameType = 1
};
};
// T是否继承自U或则两者是同一种类型,并且U不能使void*,因为任何类型都可以转换成void*
// 加const是为了防止类型传入const而转换失败
#define TIsBaseFromU(T, U)\
(CConversion<const T*, const U*>::TCanConversionU)\
&& (!CConversion(const U* ,const void*>::SameType))
//class CConversion
//{
// typedef char Small;
// class Big
// {
// char dymmy[2];
// };
//
// static Small Test(double);
// static Big Test(...);
// static int MakeT();
//public:
// enum{CanConversion = sizeof(Test(MakeT())) == sizeof(char),};
//};
6、type_info
7、NullType和EmptyType
class NullType;只有声明,没有定义,是一个标记位置,不能使用的
struct Emptytype{};
8、Type Traits
类型判断,识别。通过模板特例化可判断其类型,获取其类型
template<typename T>
class CTypeTrains
{
private:
//
template<class U>
struct PointerTraits
{
enum{result = false};
typedef NullType PointeeType;
};
template<class U>
struct PointerTraits<U*>
{
enum{result = true};
typedef U PointeeType;
};
//
template<typename U>
struct PToMTraits
{
enum{result = false};
};
//template<typename U>
//struct PToMTraits<U::*>
//{
// enum{return = true};
//};
//
template<typename U>
struct UnConst
{
typedef U Result;
};
template<typename U>
struct UnConst<const U>
{
typedef U Result;
};
//
template<typename U>
struct RefrenceTraits
{
enum{result = false};
};
template<typename U>
struct RefrenceTraits<U&>
{
enum{result = true};
};
public:
enum {isPointer = PointerTraits<T>::result};
enum {isMemberPointer = PToMTraits<T>::result};
enum {isRefrence = RefrenceTraits<T>::result};
typedef typename PointerTraits<T>::PointeeType PointeeType;
typedef typename UnConst<T>::Result NonConstType; // 去除const,如果T传入的是const类型,而我们又需要申明T类型进行改变时的做法
};
另外loki库中的类型识别还支持函数指针类型识别,成员函数指针类型识别。这两个语法比较特殊,举例如下
函数指针
template <typename T>
struct IsFunctionPointerRaw
{enum{result = 0};};
template <typename T>
struct IsFunctionPointerRaw<T(*)()>
{enum {result = 1};};
template <typename T,
typename P01>
struct IsFunctionPointerRaw<T(*)(P01)>
{enum {result = 1};};
template <typename T,
typename P01, typename P02>
struct IsFunctionPointerRaw<T(*)(
P01, P02)>
{enum {result = 1};};
成员函数指针
template <typename T>
struct IsMemberFunctionPointerRaw
{enum{result = 0};};
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)()>
{enum {result = 1};};
template <typename T, typename S,
typename P01>
struct IsMemberFunctionPointerRaw<T (S::*)(P01)>
{enum {result = 1};};
template <typename T, typename S,
typename P01, typename P02>
struct IsMemberFunctionPointerRaw<T (S::*)(
P01, P02)>
{enum {result = 1};};
// 有些参数是...类型的,如printf
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)(
...)>
{enum {result = 1};};
template <typename T, typename S,
typename P01>
struct IsMemberFunctionPointerRaw<T (S::*)(
P01, ...)>
{enum {result = 1};};
template <typename T, typename S,
typename P01, typename P02>
struct IsMemberFunctionPointerRaw<T (S::*)(
P01, P02, ...)>
{enum {result = 1};};
// 有些参数是volatile类型。另外还有一些是const类型(函数类型是const)
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)() volatile>
{enum {result = 1};};
template <typename T, typename S,
typename P01>
struct IsMemberFunctionPointerRaw<T (S::*)(P01) volatile>
{enum {result = 1};};
// 是否是类的成员变量
template <class U> struct PToMTraits
{
enum { result = false };
};
template <class U, class V> struct PToMTraits<U V::*>
{
enum { result = true };
};
template <class U, class V> struct PToMTraits<U V::*&>
{
enum { result = true };
};
使用举例
void CTestThchniques::TestTypeTraits()
{
bool isPtr = CTypeTrains<int>::isPointer;
bool isPtr2 = CTypeTrains<vector<int>::iterator >::isPointer;
bool isPtr3 = CTypeTrains<int*>::isPointer;
const int i = 10;
CTypeTrains<int>::NonConstType j = 10;
j = 20;
//i = 20;
bool b1 = CTypeTrains<int>::isRefrence;
bool b2 = CTypeTrains<int&>::isRefrence;
}