
IMO, exceptions should be explicitly enabled if someone wants it. Because exceptions very hardly will be what conceptually should be used in this case. I think it may even be possible to have the three ways: - pass two functors, one being for error handling; - pass one functor, this functor should have the asio::error parameter (the way is being done now in asio); - pass one functor, but exception being enabled. Though I dont know how the functor should catch the exception that way...
As the last item seems to show, using exceptions not only isnt efficient, it makes the code uglier. Using try and catch around a call to receive the results to each different IO operation is too much code. And if someone doesnt try catch? The exception will be caught by the asio demuxer. What demuxer should do with it?
If an user is not interested to exceptions it will simply ignore them, the asio documentation explicitly states that the demuxer is transparent to exceptions thrown from handlers. The function calling demuxer::run will catch the exception. If the user is interested in catching errors will provide the error handler. I did some experiment in using a diferent *type* for each error, and using a variant-like wrapper to allow easy handling of them. A vistor object can then be applied to retrive the error type. If the user is interested in all errors it writes a templated handler that sinks all errors, else it writes operator() overloads only for those errors it is interested in. For all other errors a default strategy is used. BTW, while this works quite well in pratice, probably the litle extra safety is not worth the effort.
I'm against introduzing exceptions. But I agree it may be possible to work a little more in the error handling. But, IMO, it should be like adding helper classes for this, but not throwing exceptions.
I think too that the current asio error handling interface is fine, and it is not worth changing it a this time.