Reputation: 1300
I have third party C library. I want to use it in c++ Every function return error code. when i have to use it I have to write code like this:
int err;
err=libFun1(....);
check(err);
err=libFun2(....);
check(err);
I want to wrap this functions and avoid code duplication of check. Every of this librabry function have different number parameters. What will be a good design for this?
Upvotes: 0
Views: 145
Reputation: 19221
I can see a few ways to do this:
Since you're writing for C++, I'd probably use Template functions... the only thing negative about that option is that function argument handling (assuming the library functions accept arguments) could be a headache.
I think the C approach of a variadic Macro would work better, also providing compile-time unwrapping (vs. runtime unwrapping).
i.e. (this is only an example, I didn't even test the code)
int checkerr(int err) {
if(!err)
return 0;
// ... handle errors, exit if need be.
}
#define CALL_CLIB(fn_name, ...) checkerr((fn_name)(__VA_ARGS__))
You can use it like so:
// will print "this is only 1 example"
CALL_CLIB(printf, "this is only %d, %s", 1, "example");
You can make it also more complex, if you want, adding try
, catch
or whatever you want into the mix.
Upvotes: 0
Reputation: 217085
From given code, you may simply write
check(libFun1(/*...*/));
check(libFun2(/*...*/));
Possibly, you may want to wrap each method to have only one call from user side:
void chekedLibFun1(/*...*/) { check(libFun1(/*...*/)); }
void chekedLibFun2(/*...*/) { check(libFun2(/*...*/)); }
and so previous code becomes:
checkedLibFun1(/*...*/);
checkedLibFun2(/*...*/);
Upvotes: 0
Reputation: 2124
You can use exceptions and catch them.
One way is to use Macros like:
#include <exception>
#define THROW_ON_ERROR(libFunc) do{ \
int err = libFunc(); \
if(check(err)) \
throw std::exception(); \
}while(0); \
and you code will look like this:
try
{
THROW_ON_ERROR(libFun1);
THROW_ON_ERROR(libFun2);
}catch(const std::exception& e)
{
//handle...
}
This method is not very modern but does the job. It was just to pass the point of converting the error status code convention which is the common way in C to exception handling which is a nice way in C++ (not sure if common). Also you can use your own exceptions to pass some data. You can do the same thing by calling a function like:
#include <functional>
class LibFuncException : public std::exception
{
public:
explicit LibFuncException(int err) : m_err(err) {}
int GetError() const { return m_err; }
private:
int m_err;
};
void ThrowOnError(std::function<int()> libFunc)
{
int err = libFunc();
if(check(err)
throw LibFuncException(err);
}
and your code can:
try{
ThrowOnError(libFunc1);
ThrowOnError(libFunc2);
} catch(const LibFuncException& e)
{
std::cout << "Error: << e.GetError() << std::endl;
}
EDIT:
if your library function sometime receive arguments you can either call the ThrowOnError
with a lambda like so:
int x = 10;
const char* str = "Hello World";
ThrowOnError([x, str]() { return libFuncWithArgs(x, str); });
Or if you want to be extreme you can have a variadic template like someone suggested already
Upvotes: 1
Reputation: 2514
/edit 4: The C++11-Way using variadic templates, inspired by Gill Bates' solution:
template <typename T, class ...A> int CallWrapper(T func, A... args) {
int error = func(args...);
check(error);
return error;
}
CallWrapper(libFun1);
CallWrapper(libFun2, 4711);
CallWrapper(libFun3, 42, 23);
/edit 5: older solutions, beginning with first solution:
#define LIBFUN1() do { \
int err = libFun1(); \
check(err); \
} while (0)
#define LIBFUN2() do { \
int err = libFun2(); \
check(err); \
} while (0)
LIBFUN1();
LIBFUN2();
Put the #define
s in some header file. Please note the MISSING semicolon after the while ()
. This way, you can naively use LIBFUN1()
and so on in any context, where a statement is allowed like if (...) LIBFUN1(); else LIBFUN2();
/edit 3: Instead of using #define
s, static inline functions would do the job too:
static inline int checked_libFun1() {
int err = libFun1();
check(err);
return err;
}
static inline int checked_libFun2() {
int err = libFun2();
check(err);
return err;
}
checked_libFun1();
checked_libFun2();
/edit 2: @Myst suggested to use variadic macros that contain the name of the function to call. This could look like this:
#define call_void(name) do { \
int err = name(); \
check(err); \
} while (0)
#define call_args(name, ...) do { \
int err = name(__VA_ARGS__); \
check(err); \
} while (0)
call_void(libFun1);
call_args(libFun2, 42);
The two macros are needed because you have to distinguish between functions not accepting any arguments and functions accepting any number of arguments greater one. So, here, libFun2(42)
would be called
Upvotes: 3
Reputation: 36463
How about a templated function:
template <typename T>
int CallWrapper(T func)
{
int error = func();
check(error);
return error;
}
Then call it with CallWrapper(libFun1);
.
Upvotes: 7