息,以及非标准的信息,比如__FUNCTION__。
支持多个参数及支持多个参数及ENFORCE的自定义判断条件的自定义判断条件
ENFORCE是个很好的想法,但如果你用了某样东西却发现在实际应用中却不
如文章中宣称的那么有用,你不会感到受欺骗了吗?
我们会,并且我们已经发现ENFORCE中两个重要缺陷。
首先,通常更需要在默认的文件名,行数,和表达式信息的基础上增加——或
代之以——传入一个自定义字符串的功能。
其次,ENFORCE只用!操作符来检测非零条件。然而,在真实应用中,有时
候需要被检查的“错误”值不是零。许多使用整数返回值的API,包括在<io.h>中
的标准C文件函数,返回-1来标识一个错误。另一些API使用一个符号常量。
而COM使用更复杂的情况:如果返回值为零(就是S_OK),表示正常,如果
返回值小于零,说明有一个错误,并且返回的实际值给出了错误的信息。如果
返回值大于零,状态就是“带信息的成功”,就是说返回值中有一些有用的信息。
显然我们需要一个更灵活的检测和报告框架。我们需要能够在两个层面上配置
实施(判断条件和参数传入机制),最好在编译时配置,这样实施机制比同等
的手写代码不会有更多的开销。(有一个明智的检查总是需要做一下:当某种
抽象应用于具体情况,是否能比得上非抽象的解决方法?)
基于策略的(Policy-based)设计正适合于解决此问题。所以Enforce需要从一
个简单的类改进为一个双策略参数的模板类。第一个策略是判断条件策略(处
理检测事宜),第二个策略是抛出策略(处理构建和抛出意外对象)。
template<typename Ref, typename P, tyoename R>
class Enforcer
{
…使用两个策略(看下一部分)…
}
两个策略都有非常简单的接口。以下是默认策略:
struct DefaultPredicate
{
template <class T>
static bool Wrong(const T& obj)
{
return !obj;
}
}
struct DefaultRaiser
{
template <class T>
static void Throw(const T&, const std::string& message, const char*
locus)
{
throw std::runtime_error (message + ‘\n’ + locus);