If I want to provide a substituteable ErrorHandler class which can be used to provide different styles of handling (e.g. rethrow, log and rethrow, swallow, call some function, etc), then I can do something like the following:
ErrorHandler.h (this is long and should probably be read only after the problem, below)
template<typename Target, typename F, typename... Args>
using IsReturnType = std::is_same<std::result_of_t<F(Args...)>, Target>;
template<typename ReturnType, typename Function, typename... Args>
using EnableIfReturnType = typename std::enable_if<IsReturnType<ReturnType, Function, Args...>::value, ReturnType>::type;
class ErrorHandler
{
public:
virtual void handleException(std::exception& e);
void Throw(std::exception& e);
// Templated Try functions
};
// Return type is void
template<typename F, typename... Ts>
typename EnableIfReturnType<void, F, Ts...>
ErrorHandler::Try(F&& function, Ts&&... args) {
try {
std::forward<F>(function)(std::forward<Ts>(args)...);
}
catch (std::exception& e) {
handleException(e);
}
}
// Return type is short
template<typename F, typename... Ts>
typename EnableIfReturnType<short, F, Ts...>
ErrorHandler::Try(F&& function, Ts&&... args) {
short result = 0;
try {
result = std::forward<F>(function)(std::forward<Ts>(args)...);
if (result != 0) {
std::string msg = "getmessagehereErr";
throw std::runtime_error(msg);
}
}
catch (std::exception& e) {
handleException(e);
}
return result;
}
// Return type is other
template<typename F, typename... Ts>
typename std::enable_if<!((IsReturnType<short, F, Ts...>::value) || (IsReturnType<void, F, Ts...>::value)), std::result_of_t<F(Ts...)>>::type
ErrorHandler::Try(F&& function, Ts&&... args) {
using R = std::result_of_t<F(Ts...)>;
R result;
try {
result = std::forward<F>(function)(std::forward<Ts>(args)...);
}
catch (std::exception& e) {
handleException(e);
}
return result;
}
SomeImplementation.cpp
extern ErrorHandler *eh;
short result = eh->Try(Function, Arg1, Arg2);
// where Function(Arg1, Arg2) returns a short, although
// a different return type could be provided for a different function via the templates
This allows me to wrap function calls with Try and have the ErrorHandler pointed to be *eh (which could be a child of ErrorHandler, with different handleException(std::exception &e)
).
Real question starts here
However, if I want to throw an error from a function that I know doesn't result in an exception, I can't do this:
int result = nonThrowingFunction();
if (result) { throw std::exception("Message"); }
because that won't be passed to the ErrorHandler *eh
.
I can't directly call eh->handleException(..)
, because the default implementation is {throw;}
, and this won't work properly if the exception it is passed hasn't already been thrown.
I can call Throw(e)
with
Throw(std::exception &e) {
try {
throw e;
}
catch(std::exception &ex) {
handleException(ex);
}
}
but this slices the exception, meaning all exceptions thrown in this way become whatever type I specify for Throw
. I can't template Throw
, because I can't get a pointer to a template function (in the general case).
Is there some good solution here, or should I write out an overloaded Throw for each exception type? (And if that's the sensible solution, is there some preprocessor magic that can write the same function for a list of different arguments?)
Edited to try and clarify the point of the question, and guide readers away from the somewhat bulky template<...> Try(...)
function(s).