强制编译时约束2011-04-09 MTT工作室 Danny Kalev通用的约束和算法常常给所处理的对象强加某些限制。例如,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;
}
};