Thanks for the review.
> It raises the number of ways for doing these things from perhaps three to four, but that's not much worse - it just is confusing.
It's reasonable to look at it this way, but in one specific aspect it's going from zero to one.
Many error handling interfaces aim at unifying usage. For example, std::error_code could be THE one and only way error codes are communicated, but this hasn't happened, and it won't happen. The reason is that if error object types participate in function signatures, even functions that don't handle errors become coupled with them. It becomes impossible to write functions that are _neutral_ towards error handling. The result is a diversity of types and interfaces, as different programmers, correctly, avoid coupling most of their functions with what they consider external APIs.
Exception does not suffer from that problem: _neutrality_ is not only possible, but it is the default for any function that doesn't handle exceptions.
LEAF provides much of this _neutrality_, minus the overhead of memory allocations and dynamic casts of exception handling. I am not aware of another alternative.