教程学院
图像设计 多媒体类 机械制图 办公软件 操作系统 系统编程 网站编程 网页制作 数据库类 网络路由 网络工程 网络安全 考试认证
酷网学院
CAD
AutoCad Cam350 ProEngineer GCcam MATLAB Unigraphics SolidWorks CAXA Solid3000 Cimatron EdgeCAM
系统
安全 防火墙 病毒 WinXP Win2003 Vista
数据库
编程
网络
  网站导航: 库库中文网 · 系统编程教程 · VC语言 · VC基础教程  

强制编译时约束

教程推荐
『强制编译时约束』如果文章有大量图片,显示会较慢,请等待图片下载完成
 
点击数: 更新时间:2009-3-6 20:39:22 
原文出处:Enforcing Compile-time Constraints

摘要:实现某些约束需要太多的力气活,如果能找到某种通用方式实现那些更抽象的约束那就最好了,本文下面的解决方案将展示如何实现。



  通用的约束和算法常常给所处理的对象强加某些限制。例如,std::sort()算法需要其操作的对象元素定义 < 操作符。强制此约束很容易:编译器尝试针对给定类型调用该操作符。如果这个操作符不存在,你会得到一个编译错误:
#include <algorithm>

struct S{}; //doesn't define operator <

int main()

{

    S s[2];

    std::sort(s, s+2); // 出错: 在类型 'S'中 'operator<' 没有实现

}

  但是,要表达约束以及强制执行约束并不是一件容易的事情。很多抽象的约束比如:“必须是一个基类”或“必须是一个 POD 类型”需要来自程序员更多的灵活性和技巧。本文下面将示范如何一通用的方式实现此类约束。

如何以通用的方式强制执行对象的编译时约束?

使用“约束模板”自动强制执行编译时约束

提出问题

  假设你的应用程序需要一个接口,这个接口是用 C 或者 SQL 编写的非C++模块。为此,你需要保证传递到非C++模块的所有对象具备 POD 类型。

struct S1 { int x;}; 

class S2 { public: void func(); }; 

union S3 { struct { int x, y; } t; char c[4];};

struct S4 : S1, S2 {}; 

以上数据都是 POD 类型,而下面这些则不然:

struct C1 { 

       virtual void func(); //有一个虚函数

}; 

struct C2 { 

       struct T{ int x, y; }; 

       ~C2(); //有一个析构函数

}; 

struct C3 : virtual S1 {} ; //有一个虚拟基类


  在个别编程实现中 POD 和 非 POD 的使用是有严格区分的,在<csstddef> 中定义的标准宏 offsetof() 就是一个例子。参见下列表达式:

size_t nbytes = offsetof (S, mem);

  该表达式以字节为单位返回成员 mem 的偏移量。按照 C++ 标准,S 必须是一个 POD 类(class),结构(struct)或者联合(union),否则,结果是不确定的。所以你的任务是编写一个约束,这个约束能在编译时自动区分 POD 和 非 POD 类型。一旦违反了“必须是一个 POD 类型”约束,编译器便会发出明确的出错信息。


实现约束

  约束实际上就是在某个类模板的成员函数中的一个表达式或者是一个声明。当约束被违反后,上述的表达式便触发一个编译错误。具有挑战的地方是要找到正确的编译时表达式,在约束被违反时激活这些表达式。此时熟悉 C++ 标准当然是有益而无害的。标准中说非 POD 对象不能是一个联合(union)的成员(见标准的 clause 9.5)。利用这个限制,创建一个联合,让其唯一成员就是你要测试的对象不就行了。

template <class T> struct POD_test

{

	POD_test()

	{

		union 

		{

			T t; //T 必须是一个 POD 类型

		} u;

	}

};

  编译器只为实际被调用的成员函数产生代码,或者显式或者隐式。因此,在某个类模板的构造函数或吸构函数中实现该约束将保证其编译时能处理其每个实例。(稍后我们将看到如何改进此设计)
为了测试这段代码,你可以使用各种不同的模版参数来进行实例化:

//下列三条语句通过编译

POD_test <int> pi;

POD_test <S1> ps1;

POD_test <S4> ps4;



//编译失败

POD_test <std::string> pstr;

POD_test <C1> pc1;

POD_test <C2> pc2;

正像我们期望的那样,由于后面三个实例其模板参数不是 POD 对象,编译器在处理时发出了出错信息。

改进设计

  约束能导致运行时和空间上的开销吗?如果它在编译时检查,你肯定不想让它呆在可执行文件中,现代 IDEs 都很聪明, 将可执行文件中不必要的代码优化掉。为了让编译器报错,将约束移到一个单独的静态成员函数 constraints() 中(你也可以另外的函数名)。记住声明时时这个成员是 private,以便其它程序无法调用它:


template <class T> struct POD_test

{

	POD_test(){constraints();} // 强制编译时处理

private:

	static void constraints()

	{

		union{ T t;} u;

	}

};

  注意 constraints() 函数实际上什么也没做,它只是声明了一个局部联合类型的变量。由于该联合变量没有被使用,编译器可以省略掉这个构造函数中的 constraints(),从而避免了必要的开销。
“必须是 POD ” 只是众多强制约束中一个案例。另一个常用的约束是“必须是 T”,实现这个约束也非常简单:

//检查 T1 是否为 T2

template <class T1, class T2> struct is_a_T2

{

	is_a_T2() {constraints();}

	static void constraints()

	{

		T1 t1;

		T2& ref=t1; // 如果 t1 不是 t2 则出错

	}

};

  这里是另外一个约束:“必须是一个整型”,这个也不难,有多种技术途径来实现。其中之一就是是使用该对象作为某个数组的下标。因为 C++ 需要整型作为下标,使用任何其它的类型都将导致编译错误。我将这个实现留给读者来做。
  作者简介
  Danny Kalev 是一名通过认证的系统分析师,专攻 C++ 和形式语言理论的软件工程师。1997 年到 2000 年期间,他是 C++ 标准委员会成员。最近他以优异成绩完成了他在普通语言学研究方面的硕士论文。 业余时间他喜欢听古典音乐,阅读维多利亚时期的文学作品,研究 Hittite、Basque 和 Irish Gaelic 这样的自然语言。其它兴趣包括考古和地理。Danny 时常到一些 C++ 论坛并定期为不同的 C++ 网站和杂志撰写文章。他还在教育机构讲授程序设计语言和应用语言课程。

】【关闭窗口
  上一页:
  下一页:后面的文章暂时没有更新了,请多关注QQgb.com
 ·网站导航: 库库中文网 · 系统编程教程 · VC语言 · VC基础教程
VC基础教程:相关文章
VC基础教程点击榜
推荐教程更深刻地讨论指针
普通教程關于vc網頁采集問題!
普通教程关于自设计地对话框类 及 对话框
普通教程强制编译时约束
普通教程调用HHA_CompileHHP编译chm工程
普通教程VS 2005 编译地程序无法运行地几
普通教程软件热点敏感帮助地完成
普通教程符号文件——Win 运用程序调整测
普通教程高效设计与彻底测试
普通教程关于调整测试时输出地字符串信息
PHOTOSHOP - 基础教程 抠图专题 蒙版专题 3DsMax 基础 设计实例 Maya设计实例
3D设计教程
advertisement
关于站点 - 广告服务 - 联系我们 - 版权隐私 - 免责声明 - 合作伙伴 - 程序支持 - 网站地图 - 返回顶部
网站文本地图
版权所有:库库中文 2005-2007 欢迎各种媒体转载我们的原创作品[转载请注明出处]
copyright ? 2005-2008 www.QQGB.com online services. all rights reserved. 蜀ICP备05015578
Optimized for 1024x768 to Firefox,Opera and MS-IE6. Site powered by EQL. 电脑硬件 电脑知识 教程学习
红盾
热爱电脑,热爱生活
拥有电脑,拥有生命
让我们享受拥有电脑的时光