我在微软的GSL中看到了这个宏:
#define GSL_CONTRACT_CHECK(type, cond) \
(GSL_LIKELY(cond) ? static_cast<void>(0) \
: gsl::details::throw_exception(gsl::fail_fast( \
"GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
让我们简化一下,忽略我不关心的部分:
#define CHECK_1(cond) \
(cond ? static_cast<void>(0) : do_something() )
现在,我会直观地写这样的东西:
#define CHECK_2(cond) \
do { \
if (not (cond)) {do_something();} \
} while(0)
我的问题:这两种 Package 机制之间有什么区别吗?是否存在某些角落用例,其中一种机制会导致一些意外的编译失误,而另一种机制则不会?
注:
- 这实际上可能是一个伪装的C问题,我不确定这里有任何真正的C++问题。
2条答案
按热度按时间ghhkc1vu1#
所以,我的技巧告诉我
CHECK_1
和CHECK_2
应该是完全等价的,只是风格的问题。我想不出为什么不是这样。@NathanOliver似乎同意。pkbketx92#
do while版本是一个语句,而三进制是一个表达式。例如,如果assert是用do/while定义的,它就不能用下面的形式
c1 ? x : c2 ? y : (assert(c3), z)
另一方面,在C语言中,只有do while形式允许任何多语句宏定义,因为三进制需要表达式作为操作数。
这种区别使C语言中的选择变得很清楚:三进制(如可能),因为宏可用于更多情况;否则就做。
在C中,在某些情况下仍然需要宏,至少在编译时禁用宏时要缩短参数计算,do while形式从来都不是最好的选择(恕我直言)。我倾向于三进制形式,或者更像C:将宏定义 Package 在立即调用的匿名lambda中。
使用lambda可以像do while一样启用多语句宏。它是一个表达式,就像三进制一样。它在将宏参数转发到lambda时启用类型安全(您需要信任编译器在运行时内联该部分,将宏参数传递给lambda可以防止宏参数和宏主体之间的名称冲突。一般来说,由于lambda捕获在默认情况下是禁用的,它提供了作用域隔离。它允许从c++17开始将varargs转换为参数包以实现灵活性和类型安全。另外,当在宏内部中断时,您可以在调试器中获得一个干净的堆栈帧。