Search code examples
c++templatesexceptionc++20variadic-templates

Catching exception types provided via template parameter pack


Is it possible to write a template function and pass it a list of exception types to handle?

I would like to implement something like this

template<class Exc1, Exc2>
auto foo()
{
    try {
        bar();
    } catch (const Exc1& e) {
        log_error(e);
    } catch (const Exc2& e) {
        log_error(e);
    }
}

but have a variable number of exception types to handle.

The following would do what I need, but of course does not compile

template<class... Exceptions>
auto foo()
{
    try {
        bar();
    } catch (const Exceptions& e...) {
        log_error(e);
    }
}

Why do I need this? I am writing a generic 'retry' mechanism that should call provided callable, retrying several times in case an exception from the list is thrown (but letting all other exceptions bubble up). Currently I bypass the problem by providing two callables: the target function and exception handler:

template<class Function, class ExceptionHandler>
auto retry(Function function, ExceptionHandler handler)
{
   for (auto i = 0; i < 3; ++i) {
       try {
           return function();
       } catch (...) {
           handler();
       }
   }
   return function();
}

auto f = [] {
    // do something and possibly throw an exception
};

auto h = [] {
    try {
        throw;
    } catch (const Exc1& e) {
        log_error(e);
    } catch (consy Exc2& e) {
        log_error(e);
    }
};

retry(f, h);

The above code works as I expect, but I was hoping for a more elegant solution.


Solution

  • you can try to use a recursion

    template<class Exception,  class... Exceptions>
    auto foo()
    {
        if constexpr (sizeof...(Exceptions) == 0)
        {
            try {
                bar();
            } catch (const Exception& e) {
                log_error(e);
            }
        }
        else
        {
            try {
                foo<Exceptions...>();
            } catch (const Exception& e) {
                log_error(e);
            }
        }
    }
    

    a working example on godbolt