Slava
Slava

Reputation: 44268

Wrap a C API function returning pointer into macro call

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

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

Barry
Barry

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

Related Questions