У меня есть внешний интерфейс, скажем, с 20 аналогичными методами. Каждый может бросить что угодно.
Итак, у меня 20 методов выглядит так:
void Call3Wrapper(int& important_parameter)
{
try
{
external_namespace::IExternal::Call3(important_parameter);
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", "Call3");
throw mynamespace::MyException("Unresolved exception");
}
}
И то же самое для каждого Call1-Call20 (звонки с разными параметрами).
Такие как:
…и так далее.
У меня хорошая функция LogIt
для всех этих случаев и нашего собственного типа MyException
, который обрабатывает все эти случаи также.
И все эти 20 (40, 60) тел функций выглядят некрасиво, потому что 90% кода в точности аналогичны проверкам try-catch. И разработчик умрет, когда ему нужно будет что-то исправить во всех них …
Существует ли метод / практика, как организовать его менее уродливо?
Что-то вроде lock-unlock-idiom в конструкторах&деструкторы, но для попробовать-поймать?
Я определенно не хочу использовать #define CALLS_CATCH_BLOCK(call_name) ...
Может быть, вы можете шаблонизировать упаковщик и вызвать его через функциональные объекты:
template<typename CALLABLE_T>
void CallWrapper(CALLABLE_T callable, const char* name)
{
try
{
callable();
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", name);
throw mynamespace::MyException("Unresolved exception");
}
}
Тогда вы можете использовать std::bind
создать вызываемый объект с параметрами, например:
CallWrapper(std::bind(&external_namespace::IExternal::Call3,
std::ref(important_parameter)),
"Call3");
(или же boost::bind
/boost::ref
для старых компиляторов)
Обратите внимание, что компилятор по-прежнему будет генерировать экземпляр шаблона для каждого отдельного CALLABLE_T
введите, но вам не нужно повторять код.
Также обратите внимание, что таким образом вы также можете вызывать и обрабатывать функции-члены классов и т. Д.
Если это будет использоваться интерфейсом API, вам все равно может понадобиться создать отдельные методы, но вместо этого вызывать шаблонную оболочку вместо повторения кода обработки исключений.
Других решений пока нет …