目前我正在使用CppUnit在C ++中编写单元测试。最近我需要检查在使用CppUnits宏的特定情况下抛出异常:
CPPUNIT_ASSERT_THROW(
boost::get<FooClassInBoostVariant>(m_boostVariantFooOrBar),
boost::bad_get);
在编译测试期间的警告让我感到惊讶(在VS2010上,但也会对其他编译器发出警告......):
warning C4127: conditional expression is constant
我研究了CppUnit的宏定义,发现了以下内容:
do { \
bool cpputExceptionThrown_ = false; \
try { \
expression; \
} catch ( const ExceptionType & ) { \
cpputExceptionThrown_ = true; \
} \
\
if ( cpputExceptionThrown_ ) \
break; \
\
CPPUNIT_NS::Asserter::fail( \
"Expected exception: " #ExceptionType \
" not thrown.", \
CPPUNIT_SOURCELINE() ); \
} while ( false )
好吧,我完全理解这是如何工作的,do while循环只执行一次,因为false,而break用于不执行Asserter :: fail()部分。但他们为什么这样做呢?它 - 当然 - 触发编译器警告,因为while循环的中断条件显然总是“假”。但是,有没有更优雅的方式来做到这一点?我通常坚持无警告编译原则,所以这真的让我烦恼。
所以我的问题是,他们为什么不这样实现它:
{ \
bool cpputExceptionThrown_ = false; \
try { \
expression; \
} catch ( const ExceptionType & ) { \
cpputExceptionThrown_ = true; \
} \
\
if ( !cpputExceptionThrown_ ) { \
CPPUNIT_NS::Asserter::fail( \
"Expected exception: " #ExceptionType \
" not thrown.", \
CPPUNIT_SOURCELINE() ); \
} \
}
提前致谢!
-Hannes
答案 0 :(得分:2)
原因是使断言成为一个陈述。考虑宏的这两种用法:
CPPUNIT_ASSERT_THROW(foo(), MyException); // a
CPPUNIT_ASSERT_THROW(foo(), MyException) // b - without trailing `;`!
doSomething();
使用他们的代码,您会收到//b
的错误,因为代码会扩展为do { ... } while (false) doSomething();
- 在条件之后您将错过;
。
使用您的代码,//b
很乐意编译,但是//a
会给您一个“空语句”警告,因为该行会扩展为{ ... };
,并使用superfluos {{1块之后。
为什么他们强制你使用;
我不知道 - 但我更喜欢//a
更多因为只有//b
之后的;
每一行。一个人不必将断言与正常陈述区分开来。
<强> PS:强>
我不确定但{ ... }
块和do {...} while(false)
语句之间可能存在更多差异,这些语句允许将断言宏放在不允许使用简单块的位置。
编辑,您可以使用lambda(在一个地方定义并调用它):
#define CPPUNIT_ASSERT_THROW(expression, ExceptionType) \
[&]() -> void { \
bool cpputExceptionThrown_ = false; \
try { \
expression; \
} catch ( const ExceptionType & ) { \
cpputExceptionThrown_ = true; \
} \
\
if ( cpputExceptionThrown_ ) \
return; \
\
CPPUNIT_NS::Asserter::fail( \
"Expected exception: " #ExceptionType \
" not thrown.", \
CPPUNIT_SOURCELINE() ); \
}()
但是,可能会有一些警告,例如:由于lambda捕获了你在表达式中使用的变量。
答案 1 :(得分:1)
好吧,我想我自己找到了答案:
http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/给出了解释。
在do { } while (false);
中包装多行宏实际上是一种常见做法。这是一种允许使用这些宏的解决方法,例如,在未支撑的if else
中。
if (condition_a)
MULTI_LINE_MACRO();
else
MULTI_LINE_MACRO_2();
结果是意外地只有第一行被执行,这肯定会导致意外行为。所以我猜他们并不完全无能......
http://kernelnewbies.org/FAQ/DoWhile0也解释了为什么我的解决方案不起作用。 if中的MULTI_LINE_MACRO();
会扩展到例如
if(condition_a)
{/ *宏观内容* /}
;
否//&lt;&lt;从来没有因为;上方。
所以我想我必须禁用警告。海湾合作委员会有一个工作组(({ MACRO })
),名为Statement Expression,但我认为这不适用于VS2010。