首页 > 代码库 > Modern C++(二)

Modern C++(二)

2.1 编译期Assertions

表达式在编译期评估所得结果是一个定值(常数),这意味着你可以利用编译器(而非代码)来做检查。这个想法是传给编译器一个语言构造,如果是非零表达式便合法。于是当你传入一个表达式而其值为0时,编译器会发出一个编译期错误的信息。

最简单的方式称为compile-time assertions。他依赖于一个事实:大小为0的array是非法的。

 

#define STATIC_CHECK {char unnamed[(expr)?1:0];}template <class To, class From>To safe_reinterpret_cast(From from){    STATIC_CHECK(sizeof(from)<=sizeof(To));	return reinterpret_cast<To>(from);}...void somePointer=...;char c=safe_reinterpret_cast<char>(somePointer);

  此时,如果在你的系统中,指针大小大于字符,编译器会抱怨你正试着产生一个长度为0 的array。

问题是,你收到的错误消息无法正确表达信息。较好的解法是以来一个名称带有意义的template。

template<bool> struct ComplieTimeError;template<> struct ComplieTimeError<true> {};#define STATIC_CHECK(expr)      (ComplieTimeError<expr>!=0>())

  

ComplieTimeError需要一个非型别参数,而且它只针对true有所定义。如果你试着具现化ComplieTimeError<false>,编译器会发出“Undefined specialization ComplieTimeError<false>”消息,这个消息比错误消息好,因为它是我们故意制造的,不是编译器或程序的bug。

为了更好的定制错误消息,可以传入一个额外引数给STATIC_CHECK,并让它在错误消息中出现,唯一分缺点是这个定制消息必须是合法的C++标示符,这个想法引出了一个改良版的CompileTimeChecker
template<bool> struct ComplieTimeChecker{    ComplieTimeChecker(...);};template<> struct ComplieTimeChecker<false> {};#define STATIC_CHECK(expr,msg)    {        class ERROR_##msg{};		(void)sizeof(ComplieTimeChecker<(expr)>(ERROR_##msg()));	}		

  假设sizeof(char)<sizeof(void*),

template<class To, class From>To safe_reinterpret_cast(From from){    STATIC_CHECK(sizeof(From)<=sizeof(To)),	       Destination_Type_Too_Narrow);     return reinterpret_cast<To>(from);}...void* somePointer=...;char c=safe_reinterpret_cast<char>(somePointer);	 

  处理完毕以后,上述的safe_reinterpret_cast会被展开成下列样子:

template<class To, class From>To safe_reinterpret_cast(From from){    {	    class ERROR_Destination_Type_Too_Narrow{};		(void)sizeof(ComplieTimeChecker<(sizeof(From)<=sizeof(To))>		            (ERROR_Destination_Type_Too_Narrow()));	}    return reinterpret_cast<To>(from);}

  这段程序定义了一个名为ERROR_Destination_Type_Too_Narrow的local class(空类),然后生成 一个性别为

ComplieTimeChecker<(sizeof(From)<=sizeof(To))>的暂时对象,并以一个型别为ERROR_Destination_Type_Too_Narrow的暂时对象加以初始化。最终sizeof会测量出这个对象的大小。

2.2 Patial Tempalte Specialization

template<class Window, class Controller>class Widget{   ...generic implemention...};

  你可以向下面这样加以特化

template<>class Widget<ModalDialog,MyController>{    ...specialized implemention...};

  其中ModalDialog和MyController是你另外定义的classes。

有了这个widget特化定义之后,如果你定义widget<ModalDialog,MyController>对象,编译器就是用上述定义,如果你定义其他泛型对象,编译器就会使用原本的泛型定义。

如果你想要针对任意window并搭配一个特定的mycontroller来特化widget。这是就需要partial template specialization机制:

template<class Window>class Widget<Window,MyController>{    ...partially specialized implemention...};

  注:1、虽然你可以全特化class template中的成员函数,当你不能偏特化它们。

             2、你不能偏特化namespace-level函数,最接近namespace-level template function偏特化机制的是函数重载,就实际运用而言那就意味着你对函数参数有很精致的特化能力。

 

2.3 Local classes

void Fun(){    class Local	{	    ...member variables...		...member function definitions...	};	...code using Local...}

  不过还是有一些限制,local calsses不能定义static成员变量,也不能访问non-static局部变量,它可以在template函数中被使用,定义于template韩函数内的local classes可以运用函数的template参数。

class Interface{public:    virtual void Fun()=0;	...};template<class T,class P>Interface* MakeAdapter(const T& obj,const P& arg){    class Local:public Interface	{	public:	    Local(const T& obj,const P& arg)		:obj_(obj),arg_(arg){}		virtual void Fun()		{		    obj_.Call(arg_);		}			private:	    T obj_;		P arg_;	};		return new Local(obj,arg);}


  

事实证明,任何也能用local classes的手法,都可以改用函数外的template classes来完成。换言之,并非一定得local classes不可,不过local classes 可以简化实作并提高符号的地域性。












Modern C++(二)