File: exception_to_result.cpp

package info (click to toggle)
boost1.90 1.90.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 593,168 kB
  • sloc: cpp: 4,190,642; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,776; makefile: 1,162; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (109 lines) | stat: -rw-r--r-- 3,649 bytes parent folder | download | duplicates (3)
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
// Copyright 2018-2024 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;
}