
All, A message a few days ago, along with my current reading of the book 'C++ Template Metaprogramming', piqued my interest in the idea of an "exception visitor". I put together a little something, and I'm wondering if people might be interested in my (rather poor, at the moment) code. Problem: When using exceptions it is very easy to end up with code that looks something like this: try { //Some code that might throw exceptions. } catch(std::logic_error&) { //Handle the exception. } catch(std::exception&) { //Handle exception. } catch(...) { //Handle everything else } With my code you can transform the above into something along these lines: struct my_exception_handler { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions; void operator()(std::exception& oError) { std::cout << "my_exception_handler::operator()(std::exception&)" << std::endl; } void operator()(std::logic_error& oError) { std::cout << "my_exception_handler::operator()(std::logic_error&)" << std::endl; } void operator()(void) { std::cout << "my_exception_handler::operator()(void)" << std::endl; } }; //Application code. try { //Some code that might throw exceptions, such as: throw std::logic_error("A sample logic error."); } catch(...) { //Magic happens here. catcher(my_exception_handler()); //This prints out "my_exception_handler::operator()(std::logic_error&)" } If anyone is interested I will post what I have for critique (I'm a relative newbie with MPL, so I will likely need a lot of help). I look forward to any and all comments. Jeremy

You seem to be replacing the sequence of catch-es (which is order-specific), with overloading (which isn't). The order is important, because in a way each catch is a more generic fallback for the previous ones. --Emil Jeremy Day wrote:
All,
A message a few days ago, along with my current reading of the book 'C++ Template Metaprogramming', piqued my interest in the idea of an "exception visitor". I put together a little something, and I'm wondering if people might be interested in my (rather poor, at the moment) code.
Problem:
When using exceptions it is very easy to end up with code that looks something like this:
try { //Some code that might throw exceptions. } catch(std::logic_error&) { //Handle the exception. } catch(std::exception&) { //Handle exception. } catch(...) { //Handle everything else }
With my code you can transform the above into something along these lines:
struct my_exception_handler { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions;
void operator()(std::exception& oError) { std::cout << "my_exception_handler::operator()(std::exception&)" << std::endl; }
void operator()(std::logic_error& oError) { std::cout << "my_exception_handler::operator()(std::logic_error&)" << std::endl; }
void operator()(void) { std::cout << "my_exception_handler::operator()(void)" << std::endl; } };
//Application code.
try { //Some code that might throw exceptions, such as: throw std::logic_error("A sample logic error."); } catch(...) { //Magic happens here. catcher(my_exception_handler()); //This prints out "my_exception_handler::operator()(std::logic_error&)" }
If anyone is interested I will post what I have for critique (I'm a relative newbie with MPL, so I will likely need a lot of help). I look forward to any and all comments.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

The exceptions will be caught in the order of the items in the exception handler's nested type argument. So in the example catcher tries std::logic_error first, and if the exception isn't of that type it tries std::exception. If the exception isn't of that type it defaults to operator()(void). So basically you take the order of the catch block (top to bottom) and "rotate" it so that the exception types appear in the list from left to right. Jeremy On 7/18/06, Emil Dotchevski <emildotchevski@hotmail.com> wrote:
You seem to be replacing the sequence of catch-es (which is order-specific), with overloading (which isn't). The order is important, because in a way each catch is a more generic fallback for the previous ones.
--Emil
Jeremy Day wrote:
All,
A message a few days ago, along with my current reading of the book 'C++ Template Metaprogramming', piqued my interest in the idea of an "exception visitor". I put together a little something, and I'm wondering if people might be interested in my (rather poor, at the moment) code.
Problem:
When using exceptions it is very easy to end up with code that looks something like this:
try { //Some code that might throw exceptions. } catch(std::logic_error&) { //Handle the exception. } catch(std::exception&) { //Handle exception. } catch(...) { //Handle everything else }
With my code you can transform the above into something along these lines:
struct my_exception_handler { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions;
void operator()(std::exception& oError) { std::cout << "my_exception_handler::operator()(std::exception&)" << std::endl; }
void operator()(std::logic_error& oError) { std::cout << "my_exception_handler::operator()(std::logic_error&)" << std::endl; }
void operator()(void) { std::cout << "my_exception_handler::operator()(void)" << std::endl; } };
//Application code.
try { //Some code that might throw exceptions, such as: throw std::logic_error("A sample logic error."); } catch(...) { //Magic happens here. catcher(my_exception_handler()); //This prints out "my_exception_handler::operator()(std::logic_error&)" }
If anyone is interested I will post what I have for critique (I'm a relative newbie with MPL, so I will likely need a lot of help). I look forward to any and all comments.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Emil Dotchevski" <emildotchevski@hotmail.com> writes:
You seem to be replacing the sequence of catch-es (which is order-specific), with overloading (which isn't). The order is important, because in a way each catch is a more generic fallback for the previous ones.
Personally I would prefer it if handlers automatically got the same order as would be provided by overload resolution. It's almost always a mistake to write catch(Base&) { ... } catch(Derived&) { ... } -- Dave Abrahams Boost Consulting www.boost-consulting.com

Personally I would prefer it if handlers automatically got the same order as would be provided by overload resolution. It's almost always a mistake to write
catch(Base&) { ... } catch(Derived&) { ... }
Surely it would be possible to reorder the type list that catcher uses (which it gets from the exception handling class, such as my_exception_handler) so that the order is always from most derived (such as Derived&) to least derived (such as Base&). Is there an MPL algorithm somewhere that will do that? I feel certain that I saw some code by Andrei Alexandrescu that did something along those lines. Jeremy

Jeremy Day wrote:
Personally I would prefer it if handlers automatically got the same order as would be provided by overload resolution. It's almost always a mistake to write
catch(Base&) { ... } catch(Derived&) { ... }
Surely it would be possible to reorder the type list that catcher uses (which it gets from the exception handling class, such as my_exception_handler) so that the order is always from most derived (such as Derived&) to least derived (such as Base&). Is there an MPL algorithm somewhere that will do that? I feel certain that I saw some code by Andrei Alexandrescu that did something along those lines.
Note the word 'almost' in Dave's statement ;?) No, I don't know any GOOD reason to write catch clauses in Base/Derived order, but I can write code that will be caught by the derived handler: struct my_exception : std::runtime_error, std::logic_error { ... }; void test() { try { throw my_exception(); } catch( const std::exception & ) {} catch( const std::runtime_error & ) {} } Now the question is - can I find a good example with an exception hierarchy designed in this way, where catching on the derived type first would break code? In priciple I can fake up the example, but how likely is it to be a problem in real-world use? -- AlisdairM

"AlisdairM" <alisdair.meredith@uk.renaultf1.com> writes:
Jeremy Day wrote:
Personally I would prefer it if handlers automatically got the same order as would be provided by overload resolution. It's almost always a mistake to write
catch(Base&) { ... } catch(Derived&) { ... }
Surely it would be possible to reorder the type list that catcher uses (which it gets from the exception handling class, such as my_exception_handler) so that the order is always from most derived (such as Derived&) to least derived (such as Base&). Is there an MPL algorithm somewhere that will do that? I feel certain that I saw some code by Andrei Alexandrescu that did something along those lines.
Note the word 'almost' in Dave's statement ;?)
Don't read too much into that.
No, I don't know any GOOD reason to write catch clauses in Base/Derived order, but I can write code that will be caught by the derived handler:
struct my_exception : std::runtime_error, std::logic_error { ... };
void test() { try { throw my_exception(); } catch( const std::exception & ) {} catch( const std::runtime_error & ) {} }
Now the question is - can I find a good example with an exception hierarchy designed in this way, where catching on the derived type first would break code? In priciple I can fake up the example, but how likely is it to be a problem in real-world use?
Not. :) -- Dave Abrahams Boost Consulting www.boost-consulting.com

I don't know a practical value of this library except probably a management of exception handlers order but I can suggest (rather theoretical at this time) modification of your code to get rid of code duplication. Classes in your example appear in mpl::vector and inside operator(): struct my_exception_handler { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions; // HERE ^^^^^^^^^^^^^^^^ void operator()(std::exception& oError); void operator()(std::logic_error& oError); // AND HERE ^^^^^^^^^^^^^^^^ void operator()(void); }; For compilers that support typeof, you could do this: struct my_exception_handler { void operator()(id<1>, std::exception& oError) const; void operator()(id<2>, std::logic_error& oError) const; void operator()(id<3> /* void */ ) const; }; Note the first agruments id<1>, id<2> and id<3>. You can get more information about how this magic works here: http://thread.gmane.org/gmane.comp.lib.boost.devel/117532 -- Alexander Nasonov Project Manager at Akmosoft ( http://www.akmosoft.com ) Blog: http://nasonov.blogspot.com Email: $(FirstName) dot $(LastName) at gmail dot com Jeremy Day wrote:
All,
A message a few days ago, along with my current reading of the book 'C++ Template Metaprogramming', piqued my interest in the idea of an "exception visitor". I put together a little something, and I'm wondering if people might be interested in my (rather poor, at the moment) code.
Problem:
When using exceptions it is very easy to end up with code that looks something like this:
try { //Some code that might throw exceptions. } catch(std::logic_error&) { //Handle the exception. } catch(std::exception&) { //Handle exception. } catch(...) { //Handle everything else }
With my code you can transform the above into something along these lines:
struct my_exception_handler { typedef boost::mpl::vector<std::logic_error, std::exception> exceptions;
void operator()(std::exception& oError) { std::cout << "my_exception_handler::operator()(std::exception&)" << std::endl; }
void operator()(std::logic_error& oError) { std::cout << "my_exception_handler::operator()(std::logic_error&)" << std::endl; }
void operator()(void) { std::cout << "my_exception_handler::operator()(void)" << std::endl; } };
//Application code.
try { //Some code that might throw exceptions, such as: throw std::logic_error("A sample logic error."); } catch(...) { //Magic happens here. catcher(my_exception_handler()); //This prints out "my_exception_handler::operator()(std::logic_error&)" }
If anyone is interested I will post what I have for critique (I'm a relative newbie with MPL, so I will likely need a lot of help). I look forward to any and all comments.
Jeremy _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 7/19/06, Alexander Nasonov <alnsn@yandex.ru> wrote:
I don't know a practical value of this library except probably a management of exception handlers order but I can suggest (rather theoretical at this time) modification of your code to get rid of code duplication.
[snip] Yea, there is definitely some code duplication going on. I think that there might be some trickery that I can with something like mpl::inherit or mpl::inherit_linearly, but I haven't had a chance to look into it yet. But that's really only peripheral to what I was trying to accomplish, which is catcher itself. Oleg's comments in [system] got me thinking about this, and it's a little itch that I've wanted to scratch for a while and just haven't gotten around to it until now. You can get more information about how this magic works here:
Thanks for the link. I'll give it a look. Jeremy

On 7/19/06, Alexander Nasonov <alnsn@yandex.ru> wrote:
I don't know a practical value of this library except probably a management of exception handlers order [...]
While this library is mostly a solution in search of a problem, I see at least a good pratical use for this. Consider a library Foo that can work both by trowing exceptions or by returning error codes (for example for perceived better performance). The return codes, instead of being a set of values, are a set of types and are returned as a variant. This means that the user of library Foo can use the exception visitor both as a variant visitor and as an exception visitor. With appropriate infrastructure, the same code can work both if the library Foo uses exceptions or uses return codes (for example, you may use exceptions by default and convert to return codes in the critical paths or where error are common and expected, with minimal changes in code). Of course Foo would use the same types both as exceptions types and as result types. I have done this once and it kind of work well. -- Giovanni P. Deretta

Looking at the code - it is also possible to find out the exact type of thrown exception without rethrow (by trying dynamic_cast<> in ordered way). I do not know how these approaches would compare in cost and side-effects on debuggers. Anyway, this library may have special handling for Emil Dotchevski's boost::exception - the handler for this would be always the last one checked. /Pavel

Pavel, On 8/9/06, Pavel Vozenilek <pavel_vozenilek@hotmail.com> wrote:
Looking at the code - it is also possible to find out the exact type of thrown exception without rethrow (by trying dynamic_cast<> in ordered way).
This would be possible if you catch something like std::exception&, but not if the error thrown is an exception not rooted in std::exception or if it is some other type, such as std::string. I do not know how these approaches would compare
in cost and side-effects on debuggers.
Neither do I. Anyway, this library may have special handling
for Emil Dotchevski's boost::exception - the handler for this would be always the last one checked.
The thing that I like about this little library is that what you handle and how you handle it is entirely up to the client code. if you want to handle Emil's excellent exception stuff you just add the functionality to your exception visitor and to the type list. Jeremy
participants (7)
-
Alexander Nasonov
-
AlisdairM
-
David Abrahams
-
Emil Dotchevski
-
Giovanni Piero Deretta
-
Jeremy Day
-
Pavel Vozenilek