// leaf_on_error_example.cpp #include #include #include #include #include namespace leaf = boost::leaf; struct error_tag {}; struct open_error {}; struct write_error {}; struct file_context { std::string path; }; struct user_context { std::string name; int privileges; }; struct chunk_context { int chunk; std::size_t size; std::time_t timestamp; }; leaf::result write_chunk(int chunk, std::size_t size) { chunk_context cc{chunk, size, std::time(nullptr)}; // Registers cc to be captured only if an error unwinds this scope. // On success the registration is discarded. [[maybe_unused]] auto ctx = leaf::on_error(cc); if (chunk == 3) // The context registered above rides along with this error // even though handlers live several frames up. return leaf::new_error(write_error{}); return {}; } leaf::result process_file(std::string path, std::string user) { error_tag tag; file_context fc{std::move(path)}; user_context uc{std::move(user), 0600}; [[maybe_unused]] auto tag_ctx = leaf::on_error(tag); [[maybe_unused]] auto file_ctx = leaf::on_error(fc); [[maybe_unused]] auto user_ctx = leaf::on_error(uc); // write_chunk knows nothing about the contexts registered here; // LEAF attaches them automatically to any error it propagates. for (int i = 0; i != 5; ++i) { auto r = write_chunk(i, 4096); if (!r) return r; } return {}; } int main() { return leaf::try_handle_all( []() -> leaf::result { // Try block and handlers must return the same type. BOOST_LEAF_CHECK(process_file("data.bin", "alice")); return 0; }, // A handler runs only if the error carries every type it // requests; handlers below with fewer parameters match the // same errors when richer contexts were never registered. [](write_error const&, error_tag const&, file_context const& f, user_context const& u, chunk_context const& c) { std::cerr << "write failed: " << "file=" << f.path << ", user=" << u.name << ", chunk=" << c.chunk << ", size=" << c.size << ", time=" << c.timestamp << '\n'; return 1; }, [](open_error const&, error_tag const&, file_context const& f, user_context const& u) { std::cerr << "open failed: " << "file=" << f.path << ", user=" << u.name << '\n'; return 2; }, [](error_tag const&, file_context const& f, user_context const& u, chunk_context const& c) { std::cerr << "unknown error: " << "file=" << f.path << ", user=" << u.name << ", chunk=" << c.chunk << '\n'; return 3; }, [](error_tag const&, file_context const& f, user_context const& u) { std::cerr << "unknown error: " << "file=" << f.path << ", user=" << u.name << '\n'; return 4; }, [] { std::cerr << "unknown error before file context\n"; return 5; } ); }