智能终端定制开发 ad
MTK/瑞芯微/高通-Android,智能模块/智能终端方案商

深度定制各类智能终端和智能硬件产品,提供硬件选型咨询、参考设计、元器件推荐、驱动开发、行业模块集成、操作系统定制与算法集成等软硬件定制服务。
contact.aspx

Android核心板产品覆盖2G、3G、4G通讯,双核、四核、八核CPU,可选的平台有MTK6580、MTK6737、MTK6750等,Android版本有5.1 6.0 7.0等。
contact.aspx

可广泛应用于低端智能POS、安防监控、车载设备、低端智能机器人、智能家居、智能硬件、工业智能手持设备、低端智能对讲设备、低端警务或执法设备、智能穿戴、贩卖机、物流柜、智能门禁系统等行业和设备。
contact.aspx

可提供以太网转串口透传,WIFI转串口透传,蓝牙转串口透传,CAN总线模拟量控制输出模块等。
contact.aspx

带3G或4G通讯功能,运行android系统,有多个串口,可以外挂各种模块:条码扫描、RFID、指纹识别、身份证识别、磁条卡、ID卡、GPS/北斗模块等。
contact.aspx

具有4G通讯功能,多个RS232或RS485接口,以太网接口,USB接口,CAN接口,多个AD输入。基于Android系统智能平台,方便APP应用开发。器件严格选型,运行稳定,质量可靠。
contact.aspx

强制编译时约束
[VC 编程] 2008-04-03



作者:Danny Kalev
编译:MTT 工作室

原文出处: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++ 网站和杂志撰写文章。他还在教育机构讲授程序设计语言和应用语言课程。
[VC 编程添加评论 | 评论/阅读(0/429)
评论
昵称
主页
内容
递交


Copyright @ 我的开发笔记     2008 - 2017         粤ICP备19155526号-1