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

时间:2018-11-27 09:04:44

标签: c++ exception-handling

如果有一些框架期望像这样的回调

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块?

3 个答案:

答案 0 :(得分:6)

利用以下事实,即当您处于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函数。它将错误转换逻辑集中到一个位置,因此您可以轻松地将一个函数与另一个处理程序进行扩展,并将其转换为使用此实用程序的所有函数。

答案 1 :(得分:2)

写一个包装为您做翻译。

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>

(这与您的答案基本相同,但具有独立功能而不是静态成员)。

答案 2 :(得分:0)

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