2
0
mirror of https://github.com/boostorg/leaf.git synced 2026-01-24 05:52:17 +00:00
Files
leaf/examples/exception_to_result.cpp
2019-04-26 12:12:53 -07:00

111 lines
3.1 KiB
C++

// Copyright (c) 2018-2019 Emil Dotchevski and Reverge Studios, Inc.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This example demonstrates how to transport exceptions thrown by a low level function
// through an intermediate context that is not exception-safe, to be handled in a high level
// function which may or may not be exception-safe.
#include <boost/leaf/capture.hpp>
#include <boost/leaf/result.hpp>
#include <boost/leaf/handle_error.hpp>
#include <boost/leaf/handle_exception.hpp>
#include <iostream>
namespace leaf = boost::leaf;
class error_base: public virtual std::exception { };
class error_a: public virtual error_base { };
class error_b: public virtual error_base { };
class error_c: public virtual error_base { };
// Lower-level library function which throws exceptions.
int compute_answer_throws()
{
switch( rand()%4 )
{
default: return 42;
case 1: throw error_a();
case 2: throw error_b();
case 3: throw error_c();
}
}
// Call compute_answer_throws, switch to result<int> for error handling.
leaf::result<int> compute_answer() noexcept
{
// Convert exceptions of types error_a and error_b to be communicated by leaf::result.
// Any other exception will be communicated as a std::exception_ptr.
return leaf::exception_to_result<error_a, error_b>(
[]
{
return compute_answer_throws();
} );
}
// Print the answer if the call to compute_answer is successful.
leaf::result<void> print_answer() noexcept
{
LEAF_AUTO( answer, compute_answer());
std::cout << "Answer: " << answer << std::endl;
return { };
}
int main()
{
// Exercise print_answer a few times and handle errors. Note that the exception objects that
// compute_answer_throws throws are not handled with leaf::catch_<>, but as regular LEAF
// error objects...
for( int i=0; i!=42; ++i )
{
leaf::try_handle_all(
[]() -> leaf::result<void>
{
LEAF_CHECK(print_answer());
return { };
},
[]( error_a const & e )
{
std::cerr << "Error A!" << std::endl;
},
[]( error_b const & e )
{
std::cerr << "Error B!" << std::endl;
},
//...except for error_c errors, which (for demonstration) are captured as exceptions
// into std::exception_ptr as "unknown" exceptions. Presumably this should not
// happen, therefore at this point we treat this situation as a logic error: we print
// diagnostic information and bail out.
[]( std::exception_ptr const * ep )
{
std::cerr << "Got unknown error!" << std::endl;
// Above, why do we take ep as a pointer? Because handle_all requires that the last
// handler matches any error and, taken as a pointer, if there isn't a std::exception_ptr
// associated with the error, the handler will still be matched (with 0 passed for ep).
// Had we taken it by value or by const &, the program would not have compiled.
if( ep )
leaf::try_catch(
[&]
{
std::rethrow_exception(*ep);
},
[]( leaf::error_info const & unmatched )
{
std::cerr << unmatched;
} );
} );
}
return 0;
}