Лучший способ абстрагировать перенос ошибок обработки C с исключениями - PullRequest
10 голосов
/ 11 июля 2019

Полезно, чтобы полезная библиотека C не предоставляла привязки C ++.Легко вызывать C из C ++, но, помимо прочего, проект C ++, вероятно, хочет исключения, а не числовые возвращаемые значения ошибок.

Есть ли какое-то конкретное соглашение или прием для преобразования в исключения без включения ifи throw с каждым вызовом функции?

Я написал это решение для упаковки вызовов gphoto2.Оборачивать шаблонную функцию в макрос неудобно (но имя функции важно для сообщений об ошибках; логика здесь похожа на perror).

Есть ли лучший метод или проект с открытым исходным кодом, который делает это особенно хорошо?

#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 Ответ

5 голосов
/ 12 июля 2019

Поскольку возможно (на практике через __PRETTY_FUNCTION__ или typeid) восстановить имя функции, к которой относится параметр шаблона, я бы (в C ++ 17) записал

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

Выражение для получения имени функции зависит от реализации, но базовый подход, который во многих случаях дает полезные результаты (хотя и с дополнительным текстом), заключается в добавлении

#include<typeinfo>
template<auto&> Symbol;

и напишите typeid(Symbol<F>).name().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...