用异常抽象包装C错误处理的最佳方法 P>一个有用的C库不提供C++绑定并不少见。从C++调用C很容易,但是在其他问题中,C++项目可能需要异常,而不是数值错误返回值。

用异常抽象包装C错误处理的最佳方法 P>一个有用的C库不提供C++绑定并不少见。从C++调用C很容易,但是在其他问题中,C++项目可能需要异常,而不是数值错误返回值。,c++,exception,C++,Exception,是否有任何特定的约定或技巧用于转换为异常,而不在每个函数调用中包含if和throw 我为包装gphoto2调用编写了这个解决方案。必须在宏中包装模板化函数是很尴尬的(但是函数名对于错误消息来说很重要;这里的逻辑类似于peror) 有没有更好的技术,或者有什么开源项目可以做到这一点 #包括 #包括 类GPHOTO2错误:公共标准::异常{ 私人: std::字符串消息; 公众: Gphoto2Error(std::string func,int err){ message=func+“:”+std

是否有任何特定的约定或技巧用于转换为异常,而不在每个函数调用中包含
if
throw

我为包装gphoto2调用编写了这个解决方案。必须在宏中包装模板化函数是很尴尬的(但是函数名对于错误消息来说很重要;这里的逻辑类似于
peror

有没有更好的技术,或者有什么开源项目可以做到这一点

#包括
#包括
类GPHOTO2错误:公共标准::异常{
私人:
std::字符串消息;
公众:
Gphoto2Error(std::string func,int err){
message=func+“:”+std::string(gp_result_as_string(err));
}
常量字符*what()常量抛出(){
返回消息.c_str();
}
};
模板
void\u gpCall(常量字符*名称、F F、Args…Args){
int ret=f(参数…);
如果(ret!=GP\U OK){
抛出GPHOTO2错误(名称、ret);
}
}
#定义gpCall(f,…)((gpCall(#f,((f)),uu VA_uargs_u)))
int main(){
GPContext*ctx=gp_context_new();
照相机*照相机;
gpCall(gp\U摄像头\新摄像头和摄像头);
gpCall(gp_camera_init、camera、ctx);
}
由于可以(在实践中,通过
\uu PRETTY\u FUNCTION\uuuu
typeid
)恢复模板参数引用的函数名,我(在C++17中)写

模板
无效gpCall(AA&…AA){
如果(int ret=f(aa…;ret!=GP\U OK)
抛出GPHOTO2错误(/*…*/,ret);
}
int main(){
GPContext*ctx=gp_context_new();
照相机*照相机;
gpCall(和摄像头);
gpCall(摄像头、ctx);
返回0;
}
获取函数名的表达式依赖于实现,但在许多情况下,产生可用结果(尽管有额外文本)的基本方法是添加

#include<typeinfo>
template<auto&> Symbol;
#包括
模板符号;

然后写
typeid(Symbol.name()

我看到有人投票以“基于主要意见”的方式结束了投票。有什么特别的批评或建议来改进这个问题吗?虽然“最佳”显然是一个意见问题(也许是我本应避免使用的一个词),但问这个特定问题使用了什么解决方案似乎是合理的(我已经写了一篇,但我相信其他许多人也遇到过同样的问题),如果有什么特别常见的习俗,我没有。-)我认为你的意图很好。
if
“必须”在某个地方
RAII
并在确实存在异常时抛出。在此基础上,您可以在构造函数中进行显式初始化(无需额外检查,因为已经涵盖了所有内容)。我没有VTC,但您如何量化“更好”?更少的代码行?开发人员出错的可能性更小?较低的运行时影响?更少的内存使用?另外,任何开源项目请求都绝对是离题的(“推荐软件库”),但您确实打算将其打包到一个类或一组类中,是吗?我不会将裸露的宏留给用户,即使这意味着将库的所有函数复制为类的成员函数(当然,您会在这些成员函数中使用宏)。为所有C函数创建包装函数,将错误代码转换为异常。如何使用
typeid
获取函数名?@geza:使用函数指针/引用实例化类模板,并询问其名称。Demanling可能是必需的(或者您的实现可能只是返回垃圾,但这很少见)。@geza。问题是“定义了实现”,这可能会限制可移植性(在当前情况下不是问题,因为它看起来…@geza好吧,这就是“定义了实现”的问题。使用一个编译器,您可能会得到您想要的,而另一个编译器可能不会(我为后一种情况提供了一个示例)。@geza我们需要一些额外的伪模板来让它工作,比如
template struct Name{}
通过这个,我得到了
typeid(Name).Name()
4NameIL_Z6memcpyEE
,对于不同类型的不同函数,“memcpy”周围的部分是相同的。。。
#include<typeinfo>
template<auto&> Symbol;