编译期的异常检测

表达式(expression)在编译期检测得到的结果是一个常数,这意味着可以利用编译期(而非代码)来作检测。

我们可以传给编译期一个语言构造(lauguage construct),如果是非零表达式则合法,零表达式则非法。当传入一个表达式而其值为零时,编译期会发出一个编译期的错我信息;

最简单的方式称为“compil-time-assertions”。它依赖一个事实:大小为零的array是非法的。

#define STATIC_CHECK(expr) { char unnamed[(expr) ?  1 : 0];}

这种方法能够产生错误,但不能表达正确信息。即产生的告警不能正确的表达错误信息。

一个较好的方法是依赖一个名称带有意义的template(因为编译期会在错误信息中指出template的名称):

template<bool> struct ComplileTimeError;
template<> struct ComplileTimeError<true> {};

#define STATIC_CHECK(expr)  \
    (ComplileTimeError<(expr)> != 0>())
ComplileTimeError需要一个非class的参数(一个bool参数),而且它只针对true有定义。
如果尝试实现ComplileTimeError<false>, 编译器会发出“undefined specialization ComplileTimeError<false>”。

这个解决了我们从无法识别的错误到我定制的错误消息,但我们可以继续改进,定制我我们的错误消息:

// 编译期 的 静态检验
template<bool> struct CompileTimeChecker {
    CompileTimeChecker(...);
};

template<> struct CompileTimeChecker<false> {};

#define STATIC_CHECK(expr, msg) {    \
    class ERROR_##msg{};    \
    (void)sizeof(CompileTimeChecker<expr>(ERROR_##msg{}));  \
}


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);
}

这样如果我们有错误,编译器会产生   无法从“safe_reinterpret_cast::ERROR_Destination_Type_Too_Narrow”转换为“CompileTimeChecker<false>”, 这样我们就可以通过编译告警知道错误的信息了。

 

posted @ 2022-08-11 15:10  菜鸟_IceLee  阅读(64)  评论(0编辑  收藏  举报