Иногда (например при состыковке библиотек) возникает подобный код:
try{
DoSomething();
}
catch(std::exception &){
throw MyError();
}
catch(DB::Exception& de){
throw MyError();
}
...
catch(...){
throw MyError();
}
ИМХО это громоздко и плохо расширяемо.
Также иногда хотелось бы в библиотеке позволить пользователю выбирать некритические исключения, обрабатываемые "на месте", задаваемые пользователем же обработчиками.
Предлагаю следующий вариант решения таких вопросов
/// генератор кортежей из последовательности типов
template< typename Types >
struct TupleGen
: boost::mpl::reverse_fold<
Types
, boost::tuples::null_type
, boost::tuples::cons<boost::mpl::_2,boost::mpl::_1>
>
{
};
class AnyException
{
};
/// обработчик исключений
template<
typename ETL,
typename HTL,
typename BT=void(*)()
>
class ExcHandler
{
public:
typedef BT BodyType;
typedef HTL HandlersTypeList;
typedef ETL ExceptionTypeList;
typedef typename TupleGen<HandlersTypeList>::type HandlersType;
ExcHandler(const BodyType &abody, const HandlersType &hd)
:body_(abody), handlers_(hd){
// Если вываливаемся тут, значит кол-во типов в массиве
// ExceptionTypeList не равно кол-ву типов в массиве HandlersTypeList.
BOOST_MPL_ASSERT_MSG(boost::mpl::size<HandlersTypeList>::type::value==
boost::mpl::size<ExceptionTypeList>::type::value,
HANDLERS_EXCEPIONS_ARRAY_MISTMATCH, (int));
}
void operator()(){
typedef typename boost::mpl::int_<boost::mpl::size<ExceptionTypeList>::value-1> TP;
this->Exec(TP());
}
private:
BodyType body_;
HandlersType handlers_;
template<typename T> void Exec(T){
typedef typename boost::mpl::at_c<ExceptionTypeList, T::value>::type CurrentExType;
TryCatch<T, CurrentExType>(boost::is_same<CurrentExType, AnyException>());
};
void Exec(boost::mpl::int_<-1>::type){
body_();
};
template<typename T, typename Ex> void TryCatch(boost::false_type){
try{
Exec(typename boost::mpl::prior<T>::type());
}
catch(Ex &ex){
boost::get<T::value>(handlers_)(ex);
}
}
template<typename T, typename Ex> void TryCatch(boost::true_type){
try{
Exec(typename boost::mpl::prior<T>::type());
}
catch(...){
AnyException e;
boost::get<T::value>(handlers_)(e);
}
}
Пример использования:
using namespace boost::mpl;
using namespace boost;
// класс исключений
class MyException{
};
// тело try-блока - должно иметь operator()()
void gg()
{
cout<<"insight try|catch"<<endl;
throw runtime_error("sdasd");
}
// обработчики исключений
void RE(runtime_error& e){cout<<"r_t handler:"<<e.what()<<endl;}
void E(exception& e){cout<<"e handler:"<<e.what()<<endl;}
void ME(MyException&){cout<<"m_e handler"<<endl;}
void Unk(AnyException &){cout<<"unknown error";}
///использование
void g(){
// типы перехватываемых исключений, AnyException - для catch(...)
typedef boost::mpl::vector
<
runtime_error, exception, MyException, AnyException
> exc;
// типы обработчиков исключений - должны иметь operator()(Exception&),
// Exception - перехватываемое исключение
typedef boost::mpl::vector
<
void(*)(runtime_error&)
, void(*)(exception&)
, void(*)(MyException&)
, void(*)(AnyException&)
> hand;
// сам обработчик, в качестве параметров передаем тело try-блока и набор обработчиков
ExcHandler<exc, hand> hd(&gg, make_tuple(&RE, &E, &ME, &Unk));
hd();
}
Или вот так:
class Handler{
public:
void operator()(runtime_error& e){cout<<"r_t handler:"<<e.what()<<endl;}
void operator()(exception& e){cout<<"e handler:"<<e.what()<<endl;}
void operator()(MyException&){cout<<"m_e handler"<<endl;}
void operator()(AnyException &){cout<<"unknown error";}
void operator()(){
cout<<"insight try|catch"<<endl;
throw MyException();
}
};
....
typedef boost::mpl::vector
<
runtime_error, exception, MyException, AnyException
> exc;
typedef boost::mpl::vector
<
Handler,
Handler,
Handler,
Handler
> hand;
Handler h;
ExcHandler<exc, hand, Handler> hd(h, make_tuple(h, h, h, h));
hd();
Поведение отличается от стандартного в случае если при обработке исключения выбрасывается исключение типа обрабатываемого ниже, то оно будет обработано ниже(т.е. если в предыдущем примере в обработчике runtime_error выкинуть например logic_error, то последне будет перехвачено обработчиком exception)
Проверялось на MSVC 7.1, gcc 4.0.0, boost 1.33.0.
Жду критики