Reputation: 44268
I am trying to wrap C API functions returning int
in some cases and pointers in other into macro that would check condition and provide diagnostics and throw exception in case of error. For functions returning int
it is simple as I do not need that int
:
#define CALL_INT( name, ... ) do { \
if( !name( __VA_ARGS__ ) ) throw std::runtime_error( #name " failed" );
} while(0)
// using it
CALL_INT( foo, arg );
but for functions returning pointer it is not that simple, as I need to check that pointer against nullptr
and then assign it to my pointer. So is it possible to write similar macro, so this expression would work:
auto ptr = CALL_PTR( foobar, arg1, arg2 );
ie it would produce code, that calls foobar( arg1, arg2 )
check result against nullptr
and make it available for assignment if no error happened.
Upvotes: 0
Views: 216
Reputation: 275585
Less magic is better
#define VERIFY( ... ) \
[&](){
auto r = __VA_ARGS__;
if (!r) throw std::runtime_error( #__VA_ARGS__ " failed" );
return r;
}()
This takes an expression. It runs it. It then tests it and throws if it fails.
If it fails, it includes the entire expression in the throw.
It then returns it.
There is less magic, in that VERIFY(bob)
is just doing bob
. You can do
int x = VERIFY( call(a,b,c) );
or
VERIFY( y = call(a,b,c) );
or whatever. The primary code run is there; only the assert wrappers are missing for when it fails.
VERIFY
is also known as a macro that does this generally.
Upvotes: 1
Reputation: 303186
The real solution is: don't use macros. Just write the you want to do inline. You, and everybody else, will thank yourself later.
The literal solution would be to just immediately invoke a lambda:
#define MAYBE_THROW(f, ...) \
[&]{ \
auto _result = f(__VA_ARGS__); \
if (!_result) throw std::runtime_error(#f " failed"); \
return _result; \
}()
MAYBE_THROW(foo, arg);
auto ptr = MAYBE_THROW(foobar, arg1, arg2);
Upvotes: 3