File: exception_to_result.cpp

package info (click to toggle)
boost1.83 1.83.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 545,632 kB
  • sloc: cpp: 3,857,086; xml: 125,552; ansic: 34,414; python: 25,887; asm: 5,276; sh: 4,799; ada: 1,681; makefile: 1,629; perl: 1,212; pascal: 1,139; sql: 810; yacc: 478; ruby: 102; lisp: 24; csh: 6
file content (110 lines) | stat: -rw-r--r-- 3,650 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright 2018-2022 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 scopes that are not exception-safe, to be
// handled in a high level function which may or may not be exception-safe.

#include <boost/leaf.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
{
    BOOST_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 as
    // exceptions, but as regular LEAF error error objects...
    for( int i=0; i!=42; ++i )
    {
        leaf::try_handle_all(
            []() -> leaf::result<void>
            {
                BOOST_LEAF_CHECK(print_answer());
                return { };
            },

            []( error_a const & )
            {
                std::cerr << "Error A!" << std::endl;
            },

            []( error_b const & )
            {
                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;
}