If I run the following test witch Catch
bool eq(int x, int y) {
return x == y;
}
TEST_CASE("operator vs. function call") {
int x = 1;
int y = 2;
CHECK(x == y);
CHECK(eq(x, y));
}
I get the following output
/path/to/MyTest.cpp:8: Failure:
CHECK(x == y)
with expansion:
1 == 2
/path/to/MyTest.cpp:9: Failure:
CHECK(eq(x, y))
with expansion:
false
Why can Catch convert x
and y
to strings in the operator expression x == y
but not in the function call expression eq(x, y)
? Is it somehow possible to stringify the function call expression in a similar way to get output like this:
/path/to/MyTest.cpp:9: Failure:
CHECK(eq(x, y))
with expansion:
eq(1, 2)
The interesting part is this:
#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
do { \
Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
try { \
CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
( __catchResult <= expr ).endExpression(); \
CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
} \
catch( ... ) { \
__catchResult.useActiveException( resultDisposition ); \
} \
INTERNAL_CATCH_REACT( __catchResult ) \
} while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
where expr
is x == y
or eq(x, y)
.
How it works for x == y
:
__catchResult <= expr
results in __catchResult <= x == y
which is equivalent to (__catchResult <= x) == y
due to the lower precedence of <=
compared to ==
(see C++ operator precedence). __catchResult <= x
wraps x
in an object with an ==
operator, which y
gets passed to. That's how expr
gets destructured. All the rest is easy to imagine.
Why it does not work for eq(x, y)
:
__catchResult <= expr
results in __catchResult <= eq(x, y)
and eq(x, y)
is evaluated first (no destructuring).
For the same reason it does not work if the expression is surrounded by parentheses. For example, (x == y)
would lead to __catchResult <= (x == y)
in which case x == y
is evaluated first (no destructuring). That's why CHECK((x == y));
causes output
/path/to/MyTest.cpp:8: Failure:
CHECK((x == y))
with expansion:
false