By Ian D. Scott


2019-07-11 19:05:33 8 Comments

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);
}

1 comments

@Davis Herring 2019-07-11 22:27:59

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().

@geza 2019-07-12 06:31:32

How can typeid be used to get the name of the function?

@Davis Herring 2019-07-12 08:58:27

@geza: Instantiate a class template with the function pointer/reference and ask for its name. Demangling may be required (or your implementation could just return garbage, but that’s rare).

@Aconcagua 2019-07-12 09:02:55

@geza typid(...).name(). Problem is "implementation defined", which might limit portability (not an issue in current case, as it appears...)

@geza 2019-07-12 09:03:19

@DavisHerring: how can this be used inside the function (just like __PRETTY_FUNCTION__)?

@Aconcagua 2019-07-12 09:06:13

@geza typeid(F).name(). Solely, the 'garbage' case is perhaps less uncommon than expected: typeid(memcpy).name() yielded FPvS_PKvyE with MinGW on my system...

@Davis Herring 2019-07-12 09:07:00

@geza: I don’t understand the question—do you just mean typeid(MyTemplate<F>).name()? It doesn’t work on normal parameters that are pointers or references to functions, of course; you have to go to a backtrace-like library for that.

@geza 2019-07-12 09:08:12

@Aconcagua: where is the string memcpy in that string?

@Aconcagua 2019-07-12 09:11:17

@geza Well, that's the problem with "implementation defined". With one compiler, you might get what you want, with another not (me providing an example for the latter case).

@Davis Herring 2019-07-12 09:11:25

@Aconcagua: That’s “demangling required”, not “garbage”: you asked about the type of memcpy, not about a class template specialization that refers to it.

@geza 2019-07-12 09:13:16

@DavisHerring: can you put an expression here (which is inside gpCall), which contains the name of F?

@geza 2019-07-12 09:13:57

@Aconcagua: I don't think that any compiler will put memcpy there. It should contain type information, not the name.

@Aconcagua 2019-07-12 09:14:46

@geza Hm. Good point...

@Aconcagua 2019-07-12 09:16:08

This ongoing discussion makes it obvious that the answer lacks an example of how to apply typeid correctly here...

@Davis Herring 2019-07-12 09:19:16

@Aconcagua: Given the multiple strategies that might (need to) be pursued, I would think that a separate question. I did provide the simplest case above; use it with template<auto&> struct MyTemplate;.

@geza 2019-07-12 09:22:43

@DavisHerring: But this expression doesn't give the name of F, does it? Will it result, for example, gp_camera_new (or some mangled version of this)?

@Aconcagua 2019-07-12 09:25:11

@DavisHerring OK, overlooked that, sorry...

@Aconcagua 2019-07-12 09:28:19

@geza We need some additional dummy template to get it work, something like template <auto &F> struct Name { }; With this I get with typeid(Name<F>).name(): 4NameIL_Z6memcpyEE with the parts around 'memcpy' being the same for different functions with different type...

@geza 2019-07-12 09:34:30

@Aconcagua: thanks, now I see this nice trick. Maybe it's worth putting this information into the answer itself.

@Davis Herring 2019-07-12 09:39:19

@geza: I added it, but I still think a separate question would be more useful.

Related Questions

Sponsored Content

9 Answered Questions

[SOLVED] Proper way to declare custom exceptions in modern Python?

1 Answered Questions

[SOLVED] return integer from defined exception in C++

  • 2018-09-06 04:43:24
  • CompletelyLost
  • 266 View
  • 2 Score
  • 1 Answer
  • Tags:   c++ c++11

40 Answered Questions

[SOLVED] What's the best way to trim std::string?

  • 2008-10-19 19:23:07
  • Milan Babuškov
  • 617916 View
  • 731 Score
  • 40 Answer
  • Tags:   c++ trim stdstring

2 Answered Questions

[SOLVED] Error while trying to use const int std::array

1 Answered Questions

1 Answered Questions

[SOLVED] error: no matching function for call to 'std::map

  • 2015-07-10 14:10:19
  • edward edward
  • 3844 View
  • -1 Score
  • 1 Answer
  • Tags:   c++ dictionary stl

1 Answered Questions

[SOLVED] Using my custom iterator with stl algorithms

2 Answered Questions

[SOLVED] C++ - A few questions about throwing exceptions

  • 2016-02-20 20:44:08
  • The_Questioner
  • 158 View
  • 2 Score
  • 2 Answer
  • Tags:   c++ exception

2 Answered Questions

[SOLVED] C++ Exception Handling Questions

  • 2010-10-18 22:07:36
  • kaykun
  • 780 View
  • 3 Score
  • 2 Answer
  • Tags:   c++ winapi

3 Answered Questions

[SOLVED] Insert with object as key fails to compile?

  • 2010-10-09 01:10:10
  • Matt
  • 1678 View
  • 2 Score
  • 3 Answer
  • Tags:   c++ stl

Sponsored Content