Generic RETURN_IF_FALSE() macro?
Generic RETURN_IF_FALSE() macro?
我正在尝试清理一些包含数百个函数的遗留代码,其主体如下所示:
void functionWithSideEffect(Foo* foo)
{
if (foo)
{
// Use `foo' to warm the planet
...
}
}
显然,如果前提条件检查失败,静默失败并不是最好的主意,所以我想重构它:
int functionWithSideEffect(Foo* foo)
{
RETURN_IF_FALSE(foo != NULL, "foo is NULL in functionWithSideEffect!");
// Use `foo' to warm the planet
...
}
以下宏似乎适用于不返回值的函数:
#define RETURN_IF_FALSE(cond, msg)
do {
if (!(cond)) {
LOG("%sn", (msg));
assert((cond));
}
return;
} while(0)
它具有以下理想的特性:
- 使用清晰简洁
- 它不会默默地失败
- 它将在调试版本中崩溃,但尝试在发布版本中继续前进
(诚然,对于返回void
的函数,在发布版本中继续前进可能并不总是"可取的"。
对于返回值的函数,此宏可以解决问题:
#define RETURN_VALUE_IF_FALSE(cond, msg, retval )
do {
if (!(cond)) {
LOG("%sn", (msg));
assert((cond));
}
return(retval);
} while(0)
我的问题是:是否可以编写单个RETURN_IF_FALSE
宏来处理void
函数和返回值的函数?我坐下来尝试使用 varargs 宏做一些事情,很快发现我不太擅长编写复杂的宏。我从这个测试程序开始:
#include <stdio.h>
#include <assert.h>
#define RETURN_IF_FALSE(cond, msg, ... )
do {
if (!(cond)) {
fprintf(stderr, "%sn", (msg));
assert((cond));
}
return (##__VA_ARGS__);
} while(0)
int main()
{
RETURN_IF_FALSE(1 < 0, "1 is not less than 0!", -1);
return 0;
}
也许并不奇怪,它生成了以下编译错误:
g++ macro_test.cpp -o macro_test
macro_test.cpp:10:14: error: pasting "(" and "-" does not give a valid preprocessing token
return (##__VA_ARGS__);
^
macro_test.cpp:16:5: note: in expansion of macro ‘RETURN_IF_FALSE’
RETURN_IF_FALSE(1 < 0, "1 is not less than 0!", -1);
^
甚至可以用一个宏覆盖这两种情况吗?我在Linux上使用gcc 4.8.1。 (如果有帮助的话,我可以用-std=c++11
编译...
更新:为了使这个完整的循环,以下是我最终根据@Turix的回答和@Deduplicator的建议最终实现的实现,将assert()
调用上移以避免在"晴天"情况下对条件进行双重评估:
#define RETURN_IF_FALSE(cond, ... )
do {
if (!(cond)) {
const char* msg =
"Pre-condition '" #cond "' not met, returning " #__VA_ARGS__ "...";
LOG("%sn", msg);
assert((cond));
return __VA_ARGS__;
}
} while(0)
(我决定允许设置"自由格式"消息字符串并不是那么必要/有用,所以我只是从条件中生成了一个罐装消息字符串......
只需将宏return (##__VA_ARGS__);
的这一部分替换为return __VA_ARGS__ ;
,我认为它应该做您想要的(假设您将为返回值传递的内容不是一个复杂的表达式 - 如果是,则需要用括号预包装参数)。
我让它工作了。
#include <stdio.h>
#define RET_IF_FALSE(x, y, z) if (!x) { printf(y); return z; }
int a(int *p)
{
RET_IF_FALSE(p, __FUNCTION__, 0);
return *p;
}
void b(int *p)
{
RET_IF_FALSE(p, __FUNCTION__, );
}
int main()
{
int x;
x = a(&x);
b(&x);
x = a(NULL);
b(NULL);
return 0;
}
它可能不是带有尾随逗号的最漂亮的解决方案,并且根据 gcc 的 -pedantic 选项,它不符合标准。
用:
#define RET_IF_FALSE(x, y, ...) if (!x) { printf(y); return __VA_ARGS__; }
对于其余代码,同样适用于具有 pedantic 和 -std=c99 的 gcc,以及 clang++ 和 g++ 中的 -std=C++11。不确定 MS 编译器是做什么的,因为它们对标准的支持有时不太出色(而且我目前还没有 Windows 设置进行测试)。
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 伪造事实↔false
- QueryWorkingSet总是返回false
- 如何区分地图中的 0 和 false?
- 模板参数列表中的 false 在模板初始化期间计算为什么?
- Arduino-C++ bool 不会从 false 变为 true
- 当返回类型声明为 ListNode 时,我们是否可以返回 false<T>*
- 当我的 if 条件计算结果为 false 时,我的 else 块将不会执行
- 等于在 c++ 中返回 false
- strcmp 对于相等的字符序列返回 false
- std::is_class 在引用类上为 false
- ios_base::sync_with_stdio(false); cin.tie(NULL);
- C++ - 负数和正数之间的比较返回 false
- 如何使用boost定义布尔类,可能的值应该是TRUE或FALSE?
- 如何编写一个接受如下断言消息的自定义断言函数:assert(false) << "assertio
- protobuf 的 ParseFromString 函数返回 false
- WaitForMultipleObjects when bwaitall is false
- 跳转到if(false)块有问题吗
- 为什么当 while 循环中的 if 条件变为 false 时,我的函数不输出最后一条语句?
- 为什么将三个变量与 == 一起比较会计算为 false?