这里主要讲述编译期的强制,C++不直接支持约束,本节描述了常用的约束设计方法。
1.1 must_have_base约束
此约束保证两个类之间的继承关系,代码如下:template<
typename D,
typename B>
struct must_have_base
{
~must_have_base()
{
void (*p) (D*, B*) = constraints;
}
private:
static void constraints(D* pd, B* pb)
{
pb = pd;
}
};
pb是基类指针,pd是子类指针,因此pb=pd在D不是B的基类时会编译错误,从而保证了编译时检查D是否是B的基类。
但是有特殊的情况,1)D和B是同一个类。2)B是void类型。如此,做如下特化:
templatestruct must_have_base { ~must_have_base() { const int not_the_same_type = 0; int i[not_the_same_type]; } }; template struct must_have_base { ~must_have_base() { const int not_the_void = 0; int i[not_the_void]; } };
测试代码如下:
class A{};
class B : public A{};
class C : private A{};
class D;
int main(void)
{
must_have_base
oBA;
must_have_base
oCA; //error must_have_base
oDA; //error must_have_base
AVoid; //error must_have_base
oAA; //error return 0; }
仅判断public继承关系,对于private继承不予判断。
1.2 must_be_subscriptable约束
此约束用来检查是否能进行下标引用操作,即[ ]操作。代码如下:template< typename T >
struct must_be_subscriptable
{
~must_be_subscriptable()
{
void (*p) (T const &) = constraints;
}
private:
static void constraints(T const &T_is_not_subscriptable)
{
sizeof(T_is_not_subscriptable[0]);
}
};
这里使用了T_is_not_subscriptable[0]来使用[ ]操作符,编译器会进行判断,T是否重载了此操作符。 测试代码如下:
class subs
{
public:
int operator [](size_t index) const;
};
class not_subs{ };
int main(void)
{
must_be_subscriptable
oInt;
must_be_subscriptable
oIntPointer; must_be_subscriptable
oSubs; must_be_subscriptable
oNotSubs; //error return 0; }
1.3 must_be_subscriptable_as_decayable_pointer约束
此约束判断类型是否是原生指针,即形如T *p,p即是原生指针。template< typename T >
struct must_be_subscriptable_as_decayable_pointer
{
~must_be_subscriptable_as_decayable_pointer()
{
void (*p) (T const &) = constraints;
}
private:
static void constraints(T const &T_is_not_decay_subscriptable)
{
sizeof(0[T_is_not_decay_subscriptable]);
}
};
这里利用了原生指针的一个特性,即可作为下标使用,即如果定义了T *p,那么0[p]此表达式是合法的,代表着offset[pointer],与pointer[offset]等价,即p[0]。其他类型五次性质。 测试代码如下:
must_be_subscriptable_as_decayable_pointeroPSubs; must_be_subscriptable_as_decayable_pointer oRSubs; //error must_be_subscriptable_as_decayable_pointer oNPSubs; //error
1.4 must_be_pod约束
如果一个类具有非平凡的(non-trivial)构造函数、非平凡的拷贝构造函数、非平凡的析构函数,或者非平凡的赋值操作符,那么其对象不能作为联合(union)的成员。template< typename T >
struct must_be_pod
{
~must_be_pod()
{
void (*p) () = constraints;
}
private:
static void constraints()
{
union
{
T T_is_not_pod_type;
};
T_is_not_pod_type;
}
};
测试代码:
class NonPOD
{
public:
virtual ~NonPOD();
};
must_be_pod
a;
must_be_pod
b; must_be_pod
c; //error must_be_pod
d; //error
这里将void判断为非POD的类型,如果不判断void,那么需要对void做特化,如:
template<> struct must_be_pod{ };
1.5 must_be_same_size约束
用来判断两个类型的大小是一致的,代码如下:template< typename T >
struct size_of
{
enum { value = sizeof(T) };
};
template <>
struct size_of
{
enum { value = 0 };
};
template < typename T1,
typename T2>
struct must_be_same_size
{
~must_be_same_size()
{
void (*p) () = constraints;
}
private:
static void constraints()
{
const int T1_must_be_same_size_as_T2
= size_of
::value == size_of
::value; int i[T1_must_be_same_size_as_T2]; i[0]; } };
这里使用了size_of来代替sizeof,因为void类型对sizeof非法。特化时要考虑