mirror of
https://github.com/boostorg/leaf.git
synced 2026-01-24 05:52:17 +00:00
111 lines
3.1 KiB
C++
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;
|
|
}
|