gpt4 book ai didi

c++ - 如何将枚举返回值转换为 C++ 异常?

转载 作者:太空狗 更新时间:2023-10-29 20:34:50 33 4
gpt4 key购买 nike

我正在使用 C 库 libusb。 libusb 方法返回 libusb_error enum values表示错误。我希望这些方法改为抛出异常。

每个 libusb 错误都有一个描述,可以通过 libusb_strerror() 函数检索。我希望这是抛出异常的 what() 方法返回的内容。

我的第一次尝试涉及一个包装函数,该函数抛出一个构造有错误描述的 std::runtime_error:

libusb_error wrapper(libusb_error error) {
if(error >= 0) return error;
throw std::runtime_error(libusb_strerror(error));
}

但是使用这种方法意味着我不能只捕获 libusb 错误,也不能捕获特定的 libusb 错误。

然后我为 libusb 错误制作了 std::exception 的模板化子类:

template<libusb_error error>
class LIBUSBError : public std::exception {
using std::exception::exception;
virtual const char* what() const throw() {
return libusb_strerror(error);
}
};

这种方法使我能够捕获特定的 libusb 错误。但是,模板参数必须是常量表达式,这要求我在包装函数中为每个枚举值使用多个语句:

// * * *

libusb_error wrapper(libusb_error error) {
if(error >= 0) return error;
if(error == LIBUSB_ERROR_IO) {
throw LIBUSBError<LIBUSB_ERROR_IO>();
}
if(error == LIBUSB_ERROR_ACCESS) {
throw LIBUSBError<LIBUSB_ERROR_ACCESS>();
}
// ... etc
}

// * * *

try {
wrapper(libusb_open(device, &handle));
} catch(LIBUSBError<LIBUSB_ERROR_ACCESS> e) {
std::cerr << e;
continue;
}

// * * *

如何在不需要我写出每个枚举值的情况下将 libusb 方法的返回值转换为 C++ 异常?

最佳答案

我认为除了 switch 之外,没有其他方法可以将运行时值(在变量中)转换为编译时值(模板参数)。/case , if

如果您的错误在某个范围内,例如 0100您可以使用模板执行以下操作:

template<int taError> class MyException : public std::exception {
using std::exception::exception;
virtual const char* what() const throw() override {
printf("It's %d\n", taError);
return std::exception::what();
}
};

template<int taError> void selectThrow(int myErr) {
if (myErr == taError) {
throw MyException<taError>();
}
return selectThrow<taError - 1>(myErr);
}

template<> void selectThrow<0>(int) {
}

然后你可以像这样使用它:

int a = rand(); // replace with the function call that may fail
if (a != 0) { // This check is important to let success scenario proceed quickly
selectThrow <100>(a);
}

你可以做一个函数来避免写if在每个地方:

void checkThrow(int errCode) {
if(errCode != 0) {
selectThrow<100>(errCode);
// If nothing has been thrown, you can raise "unknown error" exception here
}
}

但是,如果您的错误范围对于模板元编程而言太大,那么一个选项是可变参数模板,并明确指定您处理的每个错误。

template<typename... taOthers> void throwVariadic(int) {
/* throw "unexpected error" exception here */
}

template<int taCur, int... taOthers> void throwVariadic(int errCode) {
if (taCur == errCode) {
throw MyException<taCur>();
}
return throwVariadic<taOthers...>(errCode);
}

void checkError(int errCode) {
if(errCode == 0) return;
throwVariadic<1, 3, 7, 15, 25>(errCode);
}

在上面的例子中你需要替换<1, 3, 7, 15, 25>使用您的实际错误名称:<LIBUSB_ERROR_IO, LIBUSB_ERROR_ACCESS /*, ...*/>

最后,还有一个选项可以求助于 switch/case加上宏(后者让你避免过多的打字)。

// Short for Handle LibUsb Error
#define HLUE(var) case var: throw LIBUSBError<var>();
switch(error) {
default:
/* Throw "unknown error" exception here */
case 0: return 0;
HLUE(LIBUSB_ERROR_IO)
HLUE(LIBUSB_ERROR_ACCESS)
/* etc for other codes */
}
#undef HLUE

关于c++ - 如何将枚举返回值转换为 C++ 异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46130513/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com