编译期Assertions
//动态检测
#include <cassert>
template<typename TypeOut, typename TypeIn>
TypeOut safe_reinterpret_cast(TypeIn tIn)
{
assert(sizeof(TypeIn) <= sizeof(TypeOut));
return reinterpret_cast<TypeOut>(tIn);
}
int main()
{
void* pValue = nullptr;
char nValue0 = reinterpret_cast<char>(pValue); //正常运行
char nValue1 = safe_reinterpret_cast<char>(pValue); //引发中断
return 0;
}
//静态检测,但是编译器报的错并不直接
//结合常量表达式和编译器自动检查分配0数组错误
#define STATIC_CHECK(expr) { char aTem[expr ? 1 : 0]; }
template<typename TypeOut, typename TypeIn>
TypeOut safe_reinterpret_cast(TypeIn tIn)
{
STATIC_CHECK(sizeof(TypeIn) <= sizeof(TypeOut));
return reinterpret_cast<TypeOut>(tIn);
}
int main()
{
void* pValue = nullptr;
char nValue0 = reinterpret_cast<char>(pValue); //编译通过
//char nValue1 = safe_reinterpret_cast<char>(pValue); //编译失败
//error C2466: 不能分配常量大小为 0 的数组
long long nValue2 = safe_reinterpret_cast<long long>(pValue);//编译成功
return 0;
}
//最终版:检测任意常量表达式,且能自定义编译器报错的字符串
template<bool> class CCompileTimeCheck
{
public:
CCompileTimeCheck(...);
};
template<> class CCompileTimeCheck<false> {};
#define STATIC_CHECK(expr, msg) \
{ \
class C##msg {}; \
sizeof((CCompileTimeCheck<expr> (C##msg()))); \
}
template<typename TypeOut, typename TypeIn>
TypeOut safe_reinterpret_cast(TypeIn tIn)
{
STATIC_CHECK(sizeof(TypeOut) >= sizeof(TypeIn), Szn);
return reinterpret_cast<TypeOut>(tIn);
}
int main()
{
void* pValue = nullptr;
long long nValue0 = safe_reinterpret_cast<long long>(pValue);//正常编译
char nValue1 = safe_reinterpret_cast<char>(pValue); //编译出错
/*
error C2440: “<function-style-cast>”:
无法从“safe_reinterpret_cast::CSzn”转换为“CCompileTimeCheck<false>”
*/
return 0;
}
对象构造、函数声明、名称查找的规则组合体现的一个例子
#include <cstdio>
#include <typeinfo>
class CTest
{
public:
CTest() { printf("CTest\n"); }
CTest(CTest&) { printf("CTest Copy\n"); }
};
class CTest1
{
public:
CTest1() { printf("CTest1\n"); }
CTest1(CTest&) { printf("CTest1 Create\n"); }
CTest1(CTest1&) { printf("CTest1 Copy\n"); }
};
int main()
{
{
int nV0 = double(2.2); //强制类型转换 nV0 = 2
//反汇编: 008F3E2C mov dword ptr [nV0],2
int nV1 = (double)2.2; //强制类型转换 nV1 = 2
//反汇编: 008F3E33 mov dword ptr [nV1],2
auto nV2 = int(double()); //强制类型转换 nV2 = 0
//反汇编: 008F3E3A mov dword ptr [nV2],0
auto nV3 = static_cast<int>(double());
//反汇编: 01003E25 mov dword ptr [nV3],0
auto pStr = typeid(int(double())).name();
//pStr = "int __cdecl(double (__cdecl*)(void))"
pStr = typeid((int(double()))).name();
//pStr = "int"
pStr = typeid(double()).name();
//pStr = "double __cdecl(void)"
pStr = typeid((double())).name();
//pStr = "double"
//int (double); //编译失败
int Fun(double); //函数声明
pStr = typeid(Fun).name(); //pStr = "int __cdecl(double)"
//sizeof 需要一个表达式或类型
//sizeof(Fun); //error Cun2070: “int (double)”: 非法的 sizeof 操作数
int nV4 = sizeof(Fun(1.1)); //Fun即使不进行定义,也不会报错 nV4 = 4
//反汇编: 009C3ECD mov dword ptr [nV4],4
}
{
auto Test1 = CTest1(CTest()); //输出"CTest" "CTest1 Create"
(CTest1(CTest())); //输出"CTest" "CTest1 Create"
CTest1 CTest(); //函数声明
CTest1 (CTest()); //函数声明 等价上一句
//从此 名字 CTest就不是自定义的类了,而是一个函数名称
auto it = CTest1(CTest()); //输出"Suprise" "CTest1" "CTest1 Copy"
auto it1 = CTest(); //输出"Suprise" "CTest1"
printf("");
}
return 0;
}
CTest1(CTest()) //等价于 CTest1 CTest() 此段代码是是CTest函数的定义
{
printf("Suprise\n");
return CTest1();
}
模板偏特化
- 模板类可以全特化也可以偏特化
- 模板类的成员函数只能全特化,不能偏特化(参见第一章)
- namespace-level的函数不能偏特化,但是可以被轻易的重载
常数映射为类型
- 应用场景:
有必要根据某个编译期常数调用一个或数个不同的函数
编译期实施分派(if-else switch语句)
template<int nValue>
struct IntToType
{
enum { eValue = nValue };
};
template<typename T, bool bTest>
class CTest
{
public:
void Fun()
{
//编译期分派
if (bTest)
{
tValue.SomeFun();
}
}
private:
T tValue;
};
template<typename T, bool bTest>
class CTest1
{
private:
void Fun(IntToType<true>)
{
tValue.SomeFun();
}
void Fun(IntToType<false>){}
public:
//编译期分派
void Suprise()
{
Fun(IntToType<bTest>());
}
private:
T tValue;
};
int main()
{
int nValue = 10;
auto it0 = IntToType<10>(); //编译成功
//auto it1 = IntToType<nValue>(); //编译出错
//“IntToType”: 模板参数“nValue”:“nValue”: 局部变量不能用作非类型参数
CTest<int, false> Test;
//Test.Fun(); //编译出错
CTest1<int, false> Test1;
Test1.Suprise(); //编译成功
return 0;
}
类型对类型的映射
//类型映射到类型
template<typename T>
struct STypeToType{ typedef T TypeOriginal; };
template<typename T, typename U>
T* Create(const U& u, STypeToType<T>)
{
return new T(u);
}
template<typename U>
CTest* Create(const U& u, STypeToType<CTest>)
{
//根据类型定制的版本
return new CTest(u, -1);
}
型别选择
- 一个应用场景:比如根据不同的类型,在vector中选择放置对象本身还是对象的指针
#include <vector>
#include <typeinfo>
using std::vector;
//方法一:扩展性差
template<typename T, bool bRe>
struct STest
{
typedef T* Type;
};
template<typename T>
struct STest<T, false>
{
typedef T Type;
};
//方法二:扩展性好
template<bool bRe, typename T, typename U>
struct SSelect
{
typedef T Type;
};
template<typename T, typename U>
struct SSelect<false, T, U>
{
typedef U Type;
};
int main()
{
//it0 = "int *"
auto it0 = typeid(STest<int, true>::Type).name();
//it1 = "int"
auto it1 = typeid(STest<int, false>::Type).name();
//it2 = "int"
auto it2 = typeid(SSelect<true, int, double>::Type).name();
//it3 = "double"
auto it3 = typeid(SSelect<false, int, double>::Type).name();
return 0;
}
编译期间侦查可转换性和继承性
- 面对两个陌生的类型T和U,如何得知U是否继承于T?在编译期间发掘这样的关系,意味着不必使用dynamic_cast,后者会所耗执行效率。
template<typename T, typename U>
class CConversion
{
//此类可以用于编译期间侦测类型的可转换性
typedef char Small;
class CBig { char aBuff[2]; };
//定义class CBig { char aBuff[2]; }; 确保sizeof(CBig) != sizeof(Small)
static Small Fun(U);
static CBig Fun(...);
/*
若T能转换为U则调用Fun(U), 否则调用Fun(...)
则有如下结论:
若T能转换为U : Fun返回Small
若T不能转换为U : Fun返回CBig
*/
static T MakeT();
//定义一个不完全函数,即使T类型的构造函数是private类型的也无妨
public:
enum
{
eExists = sizeof(Fun(MakeT())) == sizeof(Small)
//若T能转换为U则 Exists = true
//若T不能转换为U则 Exists = false
/*
sizeof可以用在任何表达式上,不论后者有多复杂,sizeof会直接传回大小,
不需要等到执行期才评估。这意味着sizeof可以感知重载、模板具现、转换规则
,或任何可以发生在C++表达式上的机制
*/
};
enum
{
eExistsToWay = eExists && CConversion<U, T>::eExists
};
enum
{
eSameType = false
};
};
//模板偏特化
template<typename T>
class CConversion<T, T>
{
public:
enum { eExists = true, eExistsToWay = true, eSameType = true };
};
class CFather {};
class CChild : public CFather {};
int main()
{
bool aRe0[] =
{
CConversion<double, int>::eExists, //true
CConversion<int, char*>::eExists, //false
CConversion<CChild*, CFather*>::eExists,//true
CConversion<CFather*, CChild*>::eExists,//false
};
bool aRe1[] =
{
//true
CConversion<double, int>::eExistsToWay,
//false
CConversion<CChild*, CFather*>::eExistsToWay,
};
bool aRe2[] =
{
CConversion<int, int>::eSameType, //true
CConversion<int, double>::eSameType, //false
};
return 0;
}
Type Traits
//类型判断
#include <vector>
using std::vector;
template<typename T>
class CTypeTraits
{
public:
enum
{
eNormal,
eNference,
eNormalPoint,
ePointToMember,
};
private:
template<typename U> struct STypeTest
{
enum { eResult = eNormal };
};
template<typename U> struct STypeTest<U&>
{
enum { eResult = eNference };
};
template<typename U> struct STypeTest<U* const>
{
enum { eResult = eNormalPoint };
};
template<typename U> struct STypeTest<U*>
{
enum { eResult = eNormalPoint };
};
template<typename U, typename V>
struct STypeTest<U V::*>
{
enum { eResult = ePointToMember };
};
template<typename U, typename V>
struct STypeTest<U (V::*)() const>
{
//类的常量 成员/成员函数 指针
enum { eResult = ePointToMember };
};
public:
enum { eType = STypeTest<T>::eResult };
};
struct A
{
int value;
int Fun();
};
int main()
{
//语法 : 定义一个指向类的常量成员函数的指针
vector<int>::size_type (vector<int>::*p)() const = &vector<int>::size;
char aRe[] =
{
CTypeTraits<vector<char>::iterator>::eType, //0
CTypeTraits<char>::eType, //0
CTypeTraits<char&>::eType, //1
CTypeTraits<char* const>::eType, //2
CTypeTraits<char*>::eType, //2
CTypeTraits<decltype(&A::value)>::eType, //3
CTypeTraits<decltype(&A::Fun)>::eType, //3
CTypeTraits<decltype(&vector<int>::size)>::eType, //3
};
return 0;
}
//利用偏特化 去掉 const 属性
template<typename T>
class CDelConst
{
private:
template<typename U> struct SNotConst
{
typedef U Type;
};
template<typename U> struct SNotConst<const U>
{
typedef U Type;
};
public:
typedef typename SNotConst<T>::Type Type;
};