如果我想提供一个可替换的ErrorHandler类,可用于提供不同的处理方式(例如重新抛出,记录和重新抛出,吞下,调用某些函数等),那么我可以执行以下操作:
ErrorHandler.h(这很长,应该只在下面的问题之后阅读)
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
这允许我用Try包装函数调用并将ErrorHandler指向* eh(可能是ErrorHandler的子代,具有不同的handleException(std::exception &e)
)。
真正的问题从这里开始
但是,如果我想从我知道不会导致异常的函数中抛出错误,我就不能这样做:
int result = nonThrowingFunction();
if (result) { throw std::exception("Message"); }
因为不会传递给ErrorHandler *eh
。
我无法直接致电eh->handleException(..)
,因为默认实施是{throw;}
,如果通过的例外情况已经过去,这将无法正常工作抛出。
我可以使用
调用Throw(e)
Throw(std::exception &e) {
try {
throw e;
}
catch(std::exception &ex) {
handleException(ex);
}
}
但这会切除异常,这意味着以这种方式抛出的所有异常都会成为我为Throw
指定的任何类型。我无法模板Throw
,因为我无法获得指向模板函数的指针(在一般情况下)。
这里有一些好的解决方案,还是应该为每种异常类型写出一个重载的Throw? (如果这是明智的解决方案,是否有一些预处理器魔法可以为不同参数列表编写相同的函数?)
编辑尝试澄清问题的重点,并引导读者远离有点笨重的template<...> Try(...)
函数。
答案 0 :(得分:0)
使用模板处理任何异常类型应该有效:
template<typename ExceptionType>
void Throw(ExceptionType &e) {
try {
throw e;
}
catch(ExceptionType &ex) {
handleException(ex);
}
}
答案 1 :(得分:0)
链接到显式实例化的模板通过指针工作。
因此,以下内容是有效的(或至少是可编译和单元测试传递)代码。
ErrorHandler.h
class ErrorHandler {
...
template<typename E>
void Throw(E& e);
...
}
ErrorHandler.cpp
template<typename E>
void ErrorHandler::Throw(E& e)
{
try {
throw e;
}
catch (E&e) {
handleException(e);
}
}
template void ErrorHandler::Throw<std::exception>(std::exception&);
template void ErrorHandler::Throw<std::runtime_error>(std::runtime_error&);
template void ErrorHandler::Throw<std::invalid_argument>(std::invalid_argument&);
并减少添加新异常的负担,该新异常不会被分割为向cpp文件添加额外的行,这不包括在其他任何地方,从而节省了编译时间。
如果结果会对异常进行分片,那么这也不会编译,因为那时会出现链接错误。