It is not uncommon for a useful C library to not provide C++ bindings. It's easy to call C from C++, but among other issues, a C++ project probably wants exceptions, rather than numerical error return values.
Is there any particular convention or trick for converting to exceptions without including an if
and throw
with each function call?
I wrote this solution for wrapping gphoto2 calls. Having to wrap the templated function in a macro is awkward (but the function name is kind of important for error messages; the logic here is similar to perror
).
Is there a better technique, or any open source project that does this particularly well?
#include <gphoto2/gphoto2.h>
#include <string>
class Gphoto2Error : public std::exception {
private:
std::string message;
public:
Gphoto2Error(std::string func, int err) {
message = func + ": " + std::string(gp_result_as_string(err));
}
const char *what() const throw() {
return message.c_str();
}
};
template <typename F, typename... Args>
void _gpCall(const char *name, F f, Args... args) {
int ret = f(args...);
if (ret != GP_OK) {
throw Gphoto2Error(name, ret);
}
}
#define gpCall(f, ...) ((_gpCall(#f, ((f)), __VA_ARGS__)))
int main() {
GPContext *ctx = gp_context_new();
Camera *camera;
gpCall(gp_camera_new, &camera);
gpCall(gp_camera_init, camera, ctx);
}
The C programming language does not support exception handling nor error handling. It is an additional feature offered by C. In spite of the absence of this feature, there are certain ways to implement error handling in C. Generally, in case of an error, most of the functions either return a null value or -1.
C does not provide direct support for error handling (also known as exception handling). By convention, the programmer is expected to prevent errors from occurring in the first place, and test return values from functions.
Since it’s possible (in practice, via __PRETTY_FUNCTION__
or typeid
) to recover the name of a function to which a template parameter refers, I would (in C++17) write
template<auto &F,class ...AA>
void gpCall(AA &&...aa) {
if(int ret=f(aa...); ret!=GP_OK)
throw Gphoto2Error(/* … */,ret);
}
int main() {
GPContext *ctx = gp_context_new();
Camera *camera;
gpCall<gp_camera_new>(&camera);
gpCall<gp_camera_init>(camera, ctx);
return 0;
}
The expression to obtain the function name is implementation-dependent, but a basic approach that produces usable results (albeit with extra text) in many cases is to add
#include<typeinfo>
template<auto&> Symbol;
and write typeid(Symbol<F>).name()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With