将异常从一种类型转换为另一种类型



如果有一些框架需要之类的回调

void fcn(F& data);

它可以处理ExF类型的异常。

在我的回调中,我使用了一些抛出ExL类型异常的第三方库。所以我的回调看起来像

void fcn1(F& data)
{
try
{
// call library
}
catch(const ExL& ex)
{
ExF exf = make_ExF(ex);
throw exf;
}
}

现在我想写更多的回调fcn2,fcn3。。。使用库但不想一直重复相同的try/catch。特别是,也许我会添加另一个

catch(const ExL2& ex)

块,以便将来进行多次回调。我无法更改框架和库中的代码(尤其是异常类型(。如何避免重复try/catch块?

利用这样一个事实:当您在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();
}
}

这种技术被称为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;
}   
}

现在您可以使用F data; translate(fcn, data),它的工作方式与fcn1(data)相同。

EDIT上面的代码不能作为回调使用,除非进一步包装它(例如在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;
}   
}

那么您的回叫是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;
}   
}

回调为CCD_ 5。

(这与您的答案基本相同,但使用了一个独立的函数,而不是静态成员(。

这是一个基于n.m.思想的解决方案:

void fcn1_inner(F& data)
{
// call library, no try/catch
}
template<void FCT(F& data)> struct Wrapper
{
static void FN(F& data)
{
try
{
FCT(data);
}
catch(const ExL& ex)
{
ExF exf = make_ExF(ex);
throw exf;
}
}
};

回调现在是

Wrapper<fcn1_inner>::FN

最新更新