c++templatesc++11variadic-templatesfunction-templates

How to: variadic wrapper function that catches exceptions of input function


I am trying to create a function that I can pass other functions, which will catch any errors, but otherwise simply return the return value of the function. Here's what I've tried:

#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;
}

I hope the intention is relatively clear; I want HandledCall to be able to receive any kind of function, and return its return value (as long as NULL is implicitly castable to this value in the case of an error). However, when I try to compile the above code I get these kinds of errors;

prog.cpp:10:78: error: expected primary-expression before ‘...’ token static auto HandledCall(const F& function, Args...args) -> decltype(function(...args))

Clearly I'm not doing this variadic templates thing correctly... Any suggestions?


Solution

  • Something like this?

    #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;
    }
    

    Update

    An improved version of HandledCall (Thanks to 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};
        }
    }