I've been reading some articles on how Rust does error handling using the Result<T, E>
type and to me it seems like a hybrid best-of-both-worlds (exceptions and return codes) solution which can be very useful. I think it would especially be handy for APIs where you don't really know on beforehand if certain errors are exceptional and should throw, or that they are merely an indication of something going wrong in an 'expected' way. Returning Result
allows moving that decision to the users of the API in a not too intrusive way. So I'm now debating whether or not to introduce this in a C++ project. The result class could be implemented roughly like this:
template< class T, class E = std::exception >
class result
{
public:
//constructors etc
operator bool() const
{
return !!res;
}
T& operator * ( )
{
if( !res )
{
assert( ex );
throw *ex;
}
return *res;
}
const E& exception() const
{
assert( ex );
return *ex;
}
private:
std::optional< T > res;
std::optional< E > ex;
};
So whene there is a function
result< int > Read();
callers can use either 'error-code' style:
const auto result = Read();
if( !result )
{
log.debug() << "failed read" << result.exception();
return false; //or again return a Result
}
doSomething( *result );
or 'exception' style:
try
{
doSomething( *Read() );
}
catch( const std::Exception& e )
{
//do what's needed
}
or decide they don't know how to handle exceptions from Read and let their caller in turn deal with it
doSomething( *Read() ); //throws if !result
Does this seem like a good idea in general, and are there similar principles used in existing C++ code? Or are there serious disadvantages I'm not seeing at the moment? Like is it too complicated towards the users because there are too many options or maybe because it is not a typical system used in C++?