Hel*_*sel 4 c++ exception-handling
如果有一些框架需要类似的类型的回调
void fcn(F& data);
Run Code Online (Sandbox Code Playgroud)
它可以处理ExF类型的异常.
在我的回调中,我使用的是一些抛出EXL类型异常的第三方库.所以我的回调看起来像
void fcn1(F& data)
{
try
{
// call library
}
catch(const ExL& ex)
{
ExF exf = make_ExF(ex);
throw exf;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我想写更多回调fcn2,fcn3,...使用库但不想一直重复相同的try/catch.特别是,也许我会添加另一个
catch(const ExL2& ex)
Run Code Online (Sandbox Code Playgroud)
阻止未来几次回调.我无法更改框架和库中的代码(特别是异常类型).如何避免重复try/catch块?
利用这样一个事实:当你处于一个捕获区时,你有一个"当前处理的异常",你可以throw;
再次.这允许您将逻辑移动到另一个函数中
void except_translate() {
try
{
throw;
}
catch(const ExL& ex)
{
ExF exf = make_ExF(ex);
throw exf;
}
}
void fcn1(F& data)
{
try
{
// call library
}
catch(...)
{
except_translate();
}
}
Run Code Online (Sandbox Code Playgroud)
该技术已知(用于谷歌目的)作为Lippincott功能.它将错误转换逻辑集中到一个位置,因此您可以使用另一个处理程序轻松扩展该功能,并将其转换为使用此实用程序的所有函数.
编写一个包装器来为您进行翻译。
template <typename Func, typename ... Args>
decltype(auto) translate(Func func, Args&&... args)
{
try {
return func(std::forward<Args>(args)...);
}
catch(const ExL& ex) {
ExF exf = make_ExF(ex);
throw exf;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以了F data; translate(fcn, data)
,它的工作方式与 相同fcn1(data)
。
编辑上面的代码不能作为回调,除非进一步包装它(例如在 lambda 中)。这是另一种方法:
template <typename Res, typename ... Args>
auto
translate(Res (&func)(Args...)) ->
std::function<Res(Args...)>
{
try {
return [&](Args&& ... args) { return func(std::forward<Args>(args)...); };
}
catch(const ExL& ex) {
ExF exf = make_ExF(ex);
throw exf;
}
}
Run Code Online (Sandbox Code Playgroud)
那么你的回调是translate(fcn)
.
这两种方法都很通用,如果您只需要包装一种类型的回调,这里有一个简单的方法:
template<void FCT(F& data)>
void translate(F& data)
{
try {
FCT(data);
}
catch(const ExL& ex) {
ExF exf = make_ExF(ex);
throw exf;
}
}
Run Code Online (Sandbox Code Playgroud)
回调是translate<fcn>
.
(这与您的答案基本相同,但使用独立函数而不是静态成员)。