
Dean,
1) use of dynamic_cast in the following snippet:
catch( read_error & x ) { if( exception_info * xi = dynamic_cast<exception_info *>(&x) ) if( exception_errno * err = get_errno(*xi) ) ....; //err->code() is the captured errno. //err->strerror() is the corresponding error string. }
Perhaps this will be a major barrier to adoption, since it reads more like a kludge than a way of exposing a well-thought about interface.
Would you be happy if the dynamic_cast is hidden in a function? I don't think it can be completely avoided. If you throw failed<foo>, you should catch(foo &) to handle the exception. At this point you do need a dynamic_cast to get to the exception_info sub-object. You could have a virtual function in foo to get you an exception_info *, but I don't think that this is appropriate.
This also seems like too much work for exception handling -- which seems harder to do than just creating my own exception class which derives from std::exception, and then a custom constructor that contains a copy of the information object that I know I want to be available from those that will be receiving the exception.
When you say that you can just create your own exception class, do you mean that you'd create a different exception class for each combination of context information you want to bundle in it?
Is there a good reason why you're not using a "composite-style" [see GoF composite pattern] exception if you intend to be able to add information as the exception is propagated through the try {} catch(...) {} blocks?
If you catch(...), you can't do anything to the exception object. That's why you need class exception_info: so you can catch(exception_info&) and add info to it, regardless of T in a throw failed<T>(). Or did you mean to use composite pattern to organize the information in an exception_info? Could you illustrate this with an example?
2) Have you considered using Boost.Fusion to create mappings of compile-time types to runtime values so that you can access the information objects in a type-safe manner? I'm not an expert about it, but it might be easier to do something like:
catch (exception_info & x) { my_type temp = at_key<my_type>(x.objects); };
I have to check Boost.Fusion out, but from your code above it seems to me it would be directly applicable. That's exactly what exception_info::get does: you pass it a type, it gets you a reference to the object of the specified type stored in the exception_info. --Emil