c++ do-while-0中的 Package 与(void)0中的 Package

6l7fqoea  于 2023-01-22  发布在  其他
关注(0)|答案(2)|浏览(142)

我在微软的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++问题。
ghhkc1vu

ghhkc1vu1#

所以,我的技巧告诉我CHECK_1CHECK_2应该是完全等价的,只是风格的问题。我想不出为什么不是这样。@NathanOliver似乎同意。

pkbketx9

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转换为参数包以实现灵活性和类型安全。另外,当在宏内部中断时,您可以在调试器中获得一个干净的堆栈帧。

相关问题