I would like to implement a CHECK()
function that can work like this:
int a = 1;
int b = 2;
int c = 1;
CHECK(a == b) << "check failed" << endl; // this will abort the program and print "check failed"
CHECK(a == c) << "check failed" << endl; // this will do nothing since CHECK is valid
I do not know how could I abort the program but still print out something. Do you know how to implement some function that works like this?
I would like to implement a CHECK()
function that can work like this:
int a = 1;
int b = 2;
int c = 1;
CHECK(a == b) << "check failed" << endl; // this will abort the program and print "check failed"
CHECK(a == c) << "check failed" << endl; // this will do nothing since CHECK is valid
I do not know how could I abort the program but still print out something. Do you know how to implement some function that works like this?
Share Improve this question asked Mar 2 at 10:38 Zeyu Zhang CNZeyu Zhang CN 1355 bronze badges 7 | Show 2 more comments3 Answers
Reset to default 2The way gtest (among others) implements this exact pattern is to return a RAII object which executes all its code in destructor:
class check {
public:
explicit check(bool success) : success{ success } {}
~check() {
if (!success) {
abort_with_message(s.str());
}
}
check(const check&) = delete;
check(check&&) = delete;
check& operator=(const check&) = delete;
check& operator=(check&&) = delete;
template <typename T>
check&& operator<<(const T& value) && {
if (!success) {
s << value;
}
return std::move(*this);
}
private:
bool success{};
std::stringstream s{};
};
#ifdef DEBUG
#define CHECK(predicate) check{ (predicate) }
#else
#define CHECK(predicate) check{ true }
#endif
Completing @DominikKaszewski 's answer
For io-manipulator as
std::endl
check&& operator<<(std::ostream& (*manip)(std::ostream&)) && { if (!success) { manip(s); } return std::move(*this); }
Avoid side effect when check passes.
#define CHECK(predicate) (predicate) ? check{ true } : check{ false }
Profiting than
<<
has higher priority than:
. Socondition ? stream1 : stream2 << "text";
is parsed ascondition ? stream1 : (stream2 << "text");
Fix compilation
check(check&&) = default;
as we use it explicitly :-)
Final code is:
class check {
public:
explicit check(bool success) : success{ success } {}
~check() {
if (!success) {
abort_with_message(s.str());
}
}
check(const check&) = delete;
check(check&&) = default;
check& operator=(const check&) = delete;
check& operator=(check&&) = delete;
template <typename T>
check&& operator<<(const T& value) && {
if (!success) {
s << value;
}
return std::move(*this);
}
check&& operator<<(std::ostream& (*manip)(std::ostream&)) && {
if (!success) {
manip(s);
}
return std::move(*this);
}
private:
bool success{};
std::stringstream s{};
};
#define CHECK(predicate) (predicate) ? check{ true } : check{ false }
Demo
You don't need to reinvent the wheel. assert()
itself has the ability to display error messages.
#include<cassert>
int a=1;
int b=2;
assert(a == b && "check failed"); // this will abort the program and print "Assertion failed: a == b && "check failed", file C:\Some\path\Source.cpp, line 42"
Generally speaking, if there is no reason not to, library functions should be preferred.
If you want to output something other than a string, you can put the output operation into assert()
The disadvantage is that assert()
will output unnecessary extra content.
assert(a == b || ((std::cerr << "a:" << a << ", b:" << b << '\n') && false));
/*
output:
a:1, b:2
Assertion failed: a == b || ((std::cerr << "a:" << a << ", b:" << b << '\n') && false), file C:\Some\path\Source.cpp, line 42"
*/
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745124646a4612617.html
CHECK(a==b)
expands to (a reference to) an object with anoperator<<()
, then your code streams "check failed" to that object, regardless of whether the assertion passes or fails (which seems a recipe for bugs in your error checking code that will be hard to find/resolve [a problem in code that, presumably, is required to check if some other code has failed] because you will be getting "check failed" written to some stream EVEN if the assertion succeeds). – Peter Commented Mar 2 at 11:15NDEBUG
is not defined) since makingCHECK()
a no-op (most desirable end state in production code, where it should be previously verified the assertions are true) is not possible. – Peter Commented Mar 2 at 23:19