我正在尝试创建一个可以传递其他函数的函数,它将捕获任何错误,但否则只是返回函数的返回值。这是我尝试过的:
#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: 错误:“...”标记之前需要主表达式 静态自动 HandledCall(const F& 函数, Args...args) -> decltype(函数(...args))
显然我没有正确地执行这个可变参数模板...有什么建议吗?
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();
}
}
有这样的事吗?
#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};
}
}
这是一个基于 @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 值。
包装的函数通常在编译时就已知,因此我建议通过如下所示的方式来利用它(> = c ++ 17):
#include <cstdlib>
#include <stdexcept>
#include <type_traits>
#include <utility>
template <auto F, typename... Args>
auto nonThrowingFunWrapper(Args... args)
{
using result_type = std::invoke_result_t<decltype(F), Args...>;
constexpr std::integral_constant<decltype(F), F> fun_object;
try
{
return fun_object(std::forward<Args>(args)...);
}
catch (...)
{
std::abort();
return result_type();
}
}
int foo(int bar)
{
throw std::runtime_error("foo failed");
return bar;
}
int main()
{
return nonThrowingFunWrapper<foo>(43);
}