]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/examples/exception_to_result.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / leaf / examples / exception_to_result.cpp
1 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc.
2
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 // This example demonstrates how to transport exceptions thrown by a low level function
7 // through an intermediate scopes that are not exception-safe, to be handled in a high
8 // level function which may or may not be exception-safe.
9
10 #include <boost/leaf/capture.hpp>
11 #include <boost/leaf/result.hpp>
12 #include <boost/leaf/handle_errors.hpp>
13 #include <iostream>
14
15 namespace leaf = boost::leaf;
16
17
18 class error_base: public virtual std::exception { };
19 class error_a: public virtual error_base { };
20 class error_b: public virtual error_base { };
21 class error_c: public virtual error_base { };
22
23
24 // Lower-level library function which throws exceptions.
25 int compute_answer_throws()
26 {
27 switch( rand()%4 )
28 {
29 default: return 42;
30 case 1: throw error_a();
31 case 2: throw error_b();
32 case 3: throw error_c();
33 }
34 }
35
36
37 // Call compute_answer_throws, switch to result<int> for error handling.
38 leaf::result<int> compute_answer() noexcept
39 {
40 // Convert exceptions of types error_a and error_b to be communicated by leaf::result.
41 // Any other exception will be communicated as a std::exception_ptr.
42 return leaf::exception_to_result<error_a, error_b>(
43 []
44 {
45 return compute_answer_throws();
46 } );
47 }
48
49
50 // Print the answer if the call to compute_answer is successful.
51 leaf::result<void> print_answer() noexcept
52 {
53 BOOST_LEAF_AUTO( answer, compute_answer());
54 std::cout << "Answer: " << answer << std::endl;
55 return { };
56 }
57
58
59 int main()
60 {
61 // Exercise print_answer a few times and handle errors. Note that the exception objects
62 // that compute_answer_throws throws are not handled as exceptions, but as regular
63 // LEAF error error objects...
64 for( int i=0; i!=42; ++i )
65 {
66 leaf::try_handle_all(
67 []() -> leaf::result<void>
68 {
69 BOOST_LEAF_CHECK(print_answer());
70 return { };
71 },
72
73 []( error_a const & e )
74 {
75 std::cerr << "Error A!" << std::endl;
76 },
77
78 []( error_b const & e )
79 {
80 std::cerr << "Error B!" << std::endl;
81 },
82
83 //...except for error_c errors, which (for demonstration) are captured as exceptions
84 // into std::exception_ptr as "unknown" exceptions. Presumably this should not
85 // happen, therefore at this point we treat this situation as a logic error: we print
86 // diagnostic information and bail out.
87 []( std::exception_ptr const * ep )
88 {
89 std::cerr << "Got unknown error!" << std::endl;
90
91 // Above, why do we take ep as a pointer? Because handle_all requires that the last
92 // handler matches any error and, taken as a pointer, if there isn't a std::exception_ptr
93 // associated with the error, the handler will still be matched (with 0 passed for ep).
94 // Had we taken it by value or by const &, the program would not have compiled.
95 if( ep )
96 leaf::try_catch(
97 [&]
98 {
99 std::rethrow_exception(*ep);
100 },
101 []( leaf::error_info const & unmatched )
102 {
103 std::cerr << unmatched;
104 } );
105 } );
106 }
107
108 return 0;
109 }