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 可以简化实作并提高符号的地域性。
				
时间: 2024-10-31 15:46:22

Modern C++(二)的相关文章

bzoj 4780: [Usaco2017 Open]Modern Art 2

4780: [Usaco2017 Open]Modern Art 2 Time Limit: 10 Sec  Memory Limit: 128 MB Description Having become bored with standard 2-dimensional artwork (and also frustrated at others copying her w ork), the great bovine artist Picowso has decided to switch t

从零开始,跟我一起做jblog项目(二)从Maven到Gradle

从零开始,跟我一起做jblog项目(一)引言 从零开始,跟我一起做jblog项目(二)Maven 从零开始,跟我一起做jblog项目(二)从Maven到Gradle 上一节讲到项目构建工具Maven,对JAR包的管理不可谓不强大 博主在使用maven引入Spring框架时,了解到Spring推荐使用gradle工具来构建项目 百度了一下,发现Gradle也是一套很优秀的项目构建工具 Gradle使用Groovy语言配置项目和依赖,在极大地提升灵活性和配置性之外,甚至配置代码要比XML结构的POM

iOS开发——面试篇&amp;面试总结(二)

面试总结(二) 1. 风格纠错题 修改方法有很多种,现给出一种做示例: 下面对具体修改的地方,分两部分做下介绍:硬伤部分和优化部分 .因为硬伤部分没什么技术含量,为了节省大家时间,放在后面讲,大神请直接看优化部分. 优化部分 1)enum建议使用 NS_ENUM 和 NS_OPTIONS 宏来定义枚举类型,参见官方的 Adopting Modern Objective-C 一文: 1 2 3 4 5 //定义一个枚举 typedef NS_ENUM(NSInteger, CYLSex) {   

Ansible configure management--翻译(二)

一. Getting Started with Ansible Ansible is profoundly different from other configuration management tools available today. It has been designed to make configuration easy in almost every way, from its simple English configuration syntax to its ease o

2017年考研英语二真题与答案(最新)

2017年全国硕士研究生入学统一考试英语(二) Section I Use of English Directions: Read the following text. Choose the best word (s) for each numbered blank and mark A, B, C or D on the ANSWER SHEET. (10 points) People have speculated for centuries about a future without

浅谈压缩感知(二):理论基础

主要内容: 信号的稀疏表示 编码测量(采样过程) 恢复算法(非线性) 一.信号与图像的稀疏表示 在DSP(数字信号处理)中,有个很重要的概念:变换域(某个线性空间:一组基函数支撑起来的空间) 一般而言,我们的信号都是在时域或空域中来表示,其实我们可以在其他变换域中通过某些正交基函数的线性组合来表示信号.如:sinusoids, wavelets, curvelets, Gabor functions,. . . 对于某个变换域或空间,其基函数是确定的,只要得到系数α的这一组值,即可通过该系数向量

SQLServer 2012异常问题(二)--由安装介质引发性能问题

原文:SQLServer 2012异常问题(二)--由安装介质引发性能问题 问题描述:生产环境一个数据库从SQLSERVER 2008 R2升级到SQLSERVER 2012 ,同时更换硬件,但迁移后发现性能明显下降,应用写入.读取性能下降的比较厉害: 向微软寻求帮助后得出答案,原来这与SQLSERVER的安装介质有关. 大致意思是说由于NUMA架构可以自行管理内存池,在安装了CAL的EE后,由于限制只能使用20个cores,同样内存则只能管理到20个cores涉及到的NUMA的对应的内存空间(

openstack高可用环境搭建(二):高可环境的搭建

1.   高可用方案 1.1 网络 网段划分: 管理网络:10.192.44.148~10.192.44.151(需要接网线,后台登陆,openstack各组件的endpoint使用) 外部网络:10.192.45.211-10.192.45.220,这里外部网络需要一个段,供虚拟机绑定浮动IP使用 虚拟机网络:192.168.0.0/24 (需要实际网卡,但不需要接网线) 存储集群网络(cluster ip):目前和管理网络复用,真正部署单独划分会更好 张工申请到的合法IP: 实机环境的10.

JuheNews系列之二 &#183; ToolBar+AppBarLayout+CoordinatorLayout+CollapsingToolbarLayout+NestedScrollView

JuheNews系列之二 · ToolBar+AppBarLayout+CoordinatorLayout+CollapsingToolbarLayout Android5.0重要的改变之一,除了Material Design风格的设计思想,应该就是沉浸式状态栏了吧.之前实现沉浸式的效果时,都是借助SystemBarTint来实现,或许以后你也可以丢弃这种方式了. 除此之外,由于actionbar不够灵活,项目中我一般喜欢把Activity的ActionBar去掉,然后自己在布局中写一个公用的H