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

Translate exception from one type to another

如果有一些框架需要像

这样的回调类型
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 块中时,你有一个 "currently handled exception",你可以再次 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;
   }   
}

回调是translate<fcn>.

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

这是基于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