我发现自己一次又一次地遵循相同的模式:
if((return_code = doFoo1(...)) != CODE_OK) {
log("useful log message based on return code");
// very likely to return an error code.
}
// continue
if((return_code = doFoo2(...)) != CODE_OK) {
log("useful log message based on return code");
// very likely to return an error code.
}
有任何见解如何避免这种烦人的模式并保持逻辑清洁?
答案 0 :(得分:2)
有很多方法可以解决这个问题,这里有一个基本方法:
bool CheckAndLog( int code )
{
if( code == CODE_OK )
return true;
log( "<some error based on code>" );
return false;
}
if( !CheckAndLog( doFoo1(...) ) )
return;
如果你还需要返回代码以供以后使用,你可以从CheckAndLog返回它,或者将它作为pass-by-reference参数,或者甚至将CheckAndLog变成一个存储最新错误代码并用实例化的类。要使用的(可能是作用域的)记录器实例。
更新如果您需要文件和行信息,则需要__FILE__
和__LINE__
宏,并且无需在整个地方输入简单的宏就足够了:
bool CheckAndLog( int code, const char* file, unsigned line )
{
if( code == CODE_OK )
return true;
std::cerr << "file " << file << " line " << line
<< "<errormessage>" << std::endl;
return false;
}
#define CHECK( what ) (CheckAndLog( what, __FILE__, __LINE__ ))
进一步将被调用的函数放入其中:因为它可用作宏参数,所以它由预处理器进行扩展。这意味着如果您键入CHECK( foobar( 65 ) )
,what
参数字面上会被视为foobar( 65 )
,而不是它的返回值。这是理想的,因为预处理器也可以turn that into a string:
bool CheckAndLog( int code, const char* desc, const char* file, unsigned line )
{
if( code == CODE_OK )
return true;
std::cerr << desc << " from file " << file << " line " << line
<< "<errormessage>" << std::endl;
return false;
}
#define STRINGIZE1( x ) #x
#define STRINGIZE( x ) STRINGIZE1( x )
#define CHECK( what ) (CheckAndLog( what, STRINGIZE( what ), __FILE__, __LINE__ ))
我建议不要使用CHECK
作为宏的名称,因为它经常被单元测试库使用。另外要小心,不要将你的宏(偶然或故意)重新定义为类似#define CHECK( what ) (true)
的东西,因为如果你写的话就意味着
CHECK( foobar( 65 ) )
,函数将永远不会被调用。