如何:variadic包装函数捕获输入函数的异常

时间:2014-06-18 03:59:52

标签: c++ templates c++11 variadic-templates function-templates

我正在尝试创建一个函数,我可以传递其他函数,这将捕获任何错误,但否则只返回函数的返回值。以下是我尝试过的内容:

#include <iostream>
using namespace std;

int fun(int input)
{
    return input;
}

template <typename F, typename...Args>
static auto HandledCall(const F& function, Args...args)
-> decltype(function(...args))
{
    try
    {
        return function(...args);
    }
    catch(...)
    {
        return NULL;
    }
}

int main() {
    std::cout << HandledCall(fun,1) << std::endl; // this should return 1
    std::cout << HandledCall(fun,-1) << std::endl; // this should return 0      
    return 0;
}

我希望意图相对明确;我希望HandledCall能够接收任何类型的函数,并返回其返回值(只要NULL在出现错误时可以隐式转换为此值)。但是,当我尝试编译上面的代码时,我遇到了这些错误;

  

prog.cpp:10:78:错误:在'...'标记之前预期的primary-expression   static auto HandledCall(const F&amp; function,Args ... args) - &gt;   decltype(函数(...参数))

显然,我没有正确地做这个可变参数模板的事情......有什么建议吗?

3 个答案:

答案 0 :(得分:4)

可以使用std::result_of确定函数调用的返回类型。

template<typename F, typename... Args>
typename std::result_of<F(Args...)>::type
    HandledCall(F&& func, Args&&... args)
{
    using result_type = typename std::result_of<F(Args...)>::type;
    try {
        return std::forward<F>(func)(std::forward<Args>(args)...);
    } catch(...) {
        return result_type();
    }
}

Live demo

答案 1 :(得分:3)

这样的东西?

#include <iostream>
using namespace std;

int fun(int input)
{
    return input;
}

template <typename T> struct ReturnType;

template<class Ret, class... Args>
struct ReturnType<Ret(Args...)> 
{
   typedef Ret type;
};


template <typename F, typename...Args>
static auto HandledCall(const F& function, Args...args) -> typename ReturnType<F>::type
{
    try
    {
        return function(args...);
    }
    catch(...)
    {
        return typename ReturnType<F>::type{0};
    }
}

int main() {
    std::cout << HandledCall(fun,1) << std::endl; // this should return 1
    std::cout << HandledCall(fun,-1) << std::endl; // this should return 0      
    return 0;
}

更新

HandledCall的改进版本(感谢Mankarse):

template <typename F, typename...Args>
static auto HandledCall(const F& function, Args&&...args) -> typename ReturnType<F>::type
{
    try
    {
        return function(std::forward<Args>(args)...);
    }
    catch(...)
    {
        return typename ReturnType<F>::type{0};
    }
}

答案 2 :(得分:1)

这是一个基于@Praetorian提供的解决方案的版本,但也适用于具有void返回类型的函数。其他答案无法处理这种情况的原因是明确实例化void类型的对象。

template<typename T> 
T default_value(){return {};}

template<>
void default_value<void>(){}

template<typename F, typename... Args>
typename std::result_of<F(Args...)>::type
  HandledCall(F&& func, Args&&... args)
{
  try {
      return std::forward<F>(func)(std::forward<Args>(args)...);
  } catch(...) {
      return default_value<typename std::result_of<F(Args...)>::type>();
  }
}

这样做的原因是因为标准允许在具有void返回类型的函数中显式返回void值。