A lightweight C++11-compatible error-handling mechanism

Overview

A Modern C++ Result Type

Ubuntu Build Status macOS Build Status Windows Build Status Codacy Badge Coverage Status Github Issues
Github Releases GitHub Sponsors
Try online

Result is a modern, simple, and light-weight error-handling alternative to exceptions with a rich feature-set.

Features

✔️ Offers a coherent, light-weight alternative to exceptions
✔️ Compatible with C++11 (with more features in C++14 and C++17)
✔️ Single-header, header-only solution -- easily drops into any project
✔️ Zero overhead abstractions -- don't pay for what you don't use.
✔️ No dependencies
✔️ Support for value-type, reference-type, and void-type values in result
✔️ Monadic composition functions like map, flat_map, and map_error for easy functional use
✔️ Optional support to disable all exceptions and rename the cpp namespace
✔️ Comprehensively unit tested for both static behavior and runtime validation
✔️ Incurs minimal cost when optimized, especially for trivial types

Check out the tutorial to see what other features Result offers.

If you're interested in how cpp::result deviates from std::expected proposals, please see this page.

Teaser

enum class narrow_error{ none, loss_of_data };

template <typename To, typename From>
auto try_narrow(const From& from) noexcept -> cpp::result
   
{
  
   const 
   auto to = 
   static_cast
   
    (from);

  
    if (
    static_cast
    
     (to) != from) {
    
     return 
     cpp::fail(narrow_error::loss_of_data);
  }

  
     return to;
}


     struct {
  
     template <
     typename T>
  
     auto 
     operator()(
     const T& x) -> std::string {
    
     return 
     std::to_string(x);
  }
} to_string;


     auto 
     main() -> int {
  
     assert(try_narrow
     
      uint8_t>(
      42LL).
      map(to_string) == 
      "42");
}
     
    
   
  

Try online

Quick References

Why result?

Error cases in C++ are often difficult to discern from the API. Any function not marked noexcept can be assumed to throw an exception, but the exact type of exception, and if it even derives from std::exception, is ambiguous. Nothing in the language forces which exceptions may propagate from an API, which can make dealing with such APIs complicated.

Often it is more desirable to achieve noexcept functions where possible, since this allows for better optimizations in containers (e.g. optimal moves/swaps) and less cognitive load on consumers.

Having a result type on your API not only semantically encodes that a function is able to fail, it also indicates to the caller how the function may fail, and what discrete, testable conditions may cause it to fail -- which is what this library intends to solve.

As a simple example, compare these two identical functions:

// (1)
auto to_uint32(const std::string& x) -> std::uint32_t;

// (2)
enum class parse_error { overflow=1, underflow=2, bad_input=3};
auto to_uint32(const std::string& x) noexcept -> result
   ;
  

In (1), it is ambiguous what (if anything) this function may throw on failure, or how this error case may be accounted for.

In (2), on the other hand, it is explicit that to_uint32 cannot throw -- so there is no need for a catch handler. It's also clear that it may fail for whatever reasons are in parse_error, which discretely enumerates any possible case for failure.

Compiler Compatibility

Result is compatible with any compiler capable of compiling valid C++11. Specifically, this has been tested and is known to work with:

  • GCC 5, 6, 7, 8, 9, 10
  • Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9, 10, 11
  • Apple Clang (Xcode) 10.3, 11.2, 11.3, 12.3
  • Visual Studio 2017[1], 2019

Latest patch level releases are assumed in the versions listed above.

Note: Visual Studios 2015 is not currently supported due to an internal compiler error experienced in the default constructor of result. Support for this will be added at a later time.

[1] Visual Studios 2017 is officially supported, though toolchain 14.16 has some issues properly compiling map_error due to insufficient support for SFINAE.

License

Result is licensed under the MIT License:

Copyright © 2017-2021 Matthew Rodusek

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

References

  • P0323R9: std::expected proposal was used as an inspiration for the general template structure.
  • bit::stl: the original version that seeded this repository, based off an earlier proposal version.
Issues
  • Improve CMake usage

    Improve CMake usage

    Checklist

    • [x] I have read the CONTRIBUTING guidelines
    • [x] The coding style is consistent with the rest of the library
    • [x] My branch's history is clean and coherent. This could be done through at least one of the following practices:
      • Rebasing my branch off of the branch being merged to
      • Squashing commits to create a more cohesive history
    • [x] If relevant, I have included unit-tests (for new code/bugfixes)

    Description

    I realize that my commits don't live up to your standards and that's fine for me, there is only so much grunt work I'm willing to do and I haven't adapted the CI files yet.

    Some things to note about the changes:

    • The documentation falsely claimed that modern CMake starts with 3.4, however 3.4 hasn't added anything significant that would make it modern. Modern CMake starts with 3.8, as that is the version which added meta compile features to specify the C++ standard requirement as a lower bound. The (CMAKE_)?\<LANG>_STANDARD variables/properties define an upper bound, which may decay to earlier standards.
    • The root project CML and test project CML files now only deal with their respective requirements. The root project CML must be nothing more than (almost) pure build and usage requirements of the project. Things like hardcoded conan details, compiler flags and alike are not requirements of the project, but the developer developing the library, and as such there is a separate superbuild CML file (in the all directory) that wires things together in a way that things work.
    • I haven't actually found a way to cleanly represent subprojects' requirements from a root conanfile.py and I don't write conan recipes myself, so I have no clue how to have a root conanfile.py without the test subprojects' details poisoning it. For this reason, I just dropped a conanfile.txt for catch in the test directory and called it a day. This point is also similar to the above, as the conanfile.py describes your library, not your tests and the test_package tests whether your library generates the conan package as it should and can be used as it should, nothing about your unit tests, etc.

    The following commands show how to run things, but you can also look at https://github.com/erikzenker/hsm/blob/master/.github/workflows/windows-ci.yml (this uses conan for its Boost dependency) and https://github.com/friendlyanon/cxx-static-shared-example/blob/master/.github/workflows/ci.yml (this uses a superbuild CML to build things in CI) for real world examples.

    How to build and install the library with this PR:

    cmake -S . -B build
    # nothing to build, header only
    cmake --install build
    

    How to build the tests with this PR:

    cmake -S test -B build
    cmake --build build
    (cd build; ctest)
    

    How to do the above using the superbuild with this PR:

    conan install test -if build/deps
    cmake -S all -B build/all -D "CMAKE_MODULE_PATH=${PWD}/build/deps"
    cmake --build build/all
    cmake --install build/all
    (cd build/all/sub/test; ctest)
    

    How to do the above using the superbuild with this PR on Windows (or multi-config generators in general):

    conan install test -if build\deps
    cmake -S all -B build\all -D "CMAKE_MODULE_PATH=%cd:\=/%/build/deps"
    cmake --build build\all --config Release
    cmake --install build\all --config Release
    %comspec% /C "cd build\all\sub\test & ctest -C Release"
    

    Also, I found a bug with Catch2's conan package, because it does not provide the proper module path to enable include(Catch). You should report this to them.

    For rationale behind everything in the refactored CML files you can read around in my PR to https://github.com/Dobiasd/FunctionalPlus and my commit messages in https://github.com/friendlyanon/cxx-static-shared-example

    So you may ask, how to move forward with this PR? Like I said, the list of requirements for PRs is gigantic and there is only so much mundane programming I'm willing to do. This PR shows a project structure to strive for that doesn't look like the build tooling was bolted on as an afterthough with no care put into it.
    You may take the code in this PR as is, split commits up, make them adhere to your personal guidelines.

    wontfix 
    opened by friendlyanon 2
  • Error compilling result.hpp on apple-clang.

    Error compilling result.hpp on apple-clang.

    Linux Compier: GCC 11 Mac Compiler: latest apple-clang

    The resulting code works on linux / gcc, but on mac I get:

    /result.hpp:3524:82: error: ISO C++ requires the name after '::~' to be found in the same scope as the name before '::~' [-Werror,-Wdtor-name]
    inline RESULT_INLINE_VISIBILITY RESULT_NS_IMPL::detail::result_union<T, E, false>::~result_union() noexcept(
                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
                                                                                     ::result_union
    
    opened by tcanabrava 4
Releases(v1.0.0)
  • v1.0.0(Mar 12, 2021)

    This is the official release of the Result library!

    This provides a result-API similar to other modern languages like Rust and Swift

    The full API reference for this version can be found here: v1.0.0 API

    Features

    • result<T,E> for representing fallible types
    • result<T&,E> for fallible reference types
    • result<void,E> for fallible non-value types (e.g. void returns)
    • failure<T> for disambiguation for error types
    • failure<T&> for referential access of T types
    • Support for comparison operators of result and failure types
    • Support for std::hash for result and failure types
    • Support for monadic functions for result (map, flat_map, map_error, flat_map_error, value_or, and_then)
    • Full constexpr support for result and failure (more constexpr support in C++14 and above)
    • Support for CTAD for failure types when working in C++17

    Compatibility

    This release is compatible with any C++11 compiler or later.

    In particular, it's known to be compatible with the following compilers:

    • GCC: 5, 6, 7, 8, 9, 10
    • Clang: 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9, 10, 11
    • Apple Clang (Xcode) 10.3, 11.2, 11.3, 12.3
    • Visual Studio 2017[1], 2019

    [1] Visual Studios 2017 is officially supported, though toolchain 14.16 has some issues properly compiling map_error due to insufficient support for SFINAE.

    Source code(tar.gz)
    Source code(zip)
    result.hpp(207.21 KB)
  • v0.0.1+test7(Dec 10, 2020)

  • v0.0.1+test4(Nov 30, 2020)

Owner
Matthew Rodusek
C++ Software developer by day, C++ template metaprogrammer by night.
Matthew Rodusek
Either and Maybe monads for better error-handling in C++ ↔️

neither A functional implementation of Either in C++14. buckaroo add github.com/loopperfect/neither Examples Handling Unsafe Code auto unsafe = [] {

LoopPerfect 244 Jul 4, 2022
C++17 & C++ 20 error-handling and utility extensions.

C++ 17 & C++ 20 error-handling and utility extensions. Overview STX is a collection of libraries and utilities designed to make working with C++ easie

Basit Ayantunde 428 Jul 9, 2022
Lightweight Error Augmentation Framework

LEAF A lightweight error handling library for C++11. Documentation https://boostorg.github.io/leaf/ Features Small single-header format, no dependenci

Boost.org 243 Jul 25, 2022
Investigate kernel error call stacks

retsnoop retsnoop is BPF-based tool that is meant to help debugging kernel issues. It allows to capture call stacks of kernel functions that return er

Andrii Nakryiko 32 Jul 28, 2022
HiFi error modeler and simulator with ploidy

A HiFi Shotgun Simulator Author: Gene Myers First: Aug 1, 2021 Current: Aug 1, 2021 Commands Himodel HIsim The Error Model Commands This module contai

Eugene W Myers Jr 8 Jul 15, 2022
repo to house various LLVM based SIHFT passes for RISCV 32/64 soft error resilience

compas-ft-riscv COMPAS: Compiler-assisted Software-implemented Hardware Fault Tolerance implemented in LLVM passes for the RISC-V backend Repo to hous

EDA@TUM 2 Jan 10, 2022
the LIBpcap interface to various kernel packet capture mechanism

LIBPCAP 1.x.y by The Tcpdump Group To report a security issue please send an e-mail to [email protected] To report bugs and other problems, contri

The Tcpdump Group 2k Jul 29, 2022
this repo will introduce you the mechanism and approach of gaussian blur

浅谈高斯模糊原理与实现 简介   早在高中,图像模糊就勾起我的兴趣:为什么近视眼看东西会模糊、透过毛玻璃的像为什么会模糊、以及win7的毛玻璃模糊特效是如何实现的,当时也有方式去查资料去实现这样的一个效果。转眼本科毕业,最近又出现一个比较热门的话题:国内安卓魔改系统的的实时模糊在高帧率下的表现,实时

ZHChan 7 Jun 2, 2022
CacheLib is a C++ library providing in-process high performance caching mechanism.

Pluggable in-process caching engine to build and scale high performance services

Facebook 702 Jul 29, 2022
An efficient and versatile system call hook mechanism

Zpoline: hooking system calls without pain Zpoline is a novel system call hook mechanism that offers the following advantages. 100 times faster than p

null 88 May 26, 2022
BLEND: A Fast, Memory-Efficient, and Accurate Mechanism to Find Fuzzy Seed Matches

BLEND is a mechanism that can efficiently find fuzzy seed matches between sequences to significantly improve the performance and accuracy while reducing the memory space usage of two important applications: 1) finding overlapping reads and 2) read mapping.

SAFARI Research Group at ETH Zurich and Carnegie Mellon University 11 Jul 29, 2022
An unidentifiable mechanism that helps you bypass GFW.

trojan An unidentifiable mechanism that helps you bypass GFW. Trojan features multiple protocols over TLS to avoid both active/passive detections and

Trojan-GFW 16.2k Jul 31, 2022
GECOS: A lock-free synchronization mechanism

GECOS GECOS is a lock-free synchronization mechanism, and this repository compares various well-known mechanisms such as RCU and HP (Hazard Pointers).

null 6 Sep 9, 2021
agent-less and lightweight communication library compatible with rclcpp for embedded devices

mros2 mros2 (formally mROS 2) realizes an agent-less and lightweight runtime environment compatible with ROS 2 for embedded devices. It consists of ba

null 99 Jul 26, 2022
KoanLogic 385 Aug 9, 2022
:hocho: Strictly RFC 3986 compliant URI parsing and handling library written in C89; moved from SourceForge to GitHub

uriparser uriparser is a strictly RFC 3986 compliant URI parsing and handling library written in C89 ("ANSI C"). uriparser is cross-platform, fast, su

uriparser 247 Jul 24, 2022
Epoxy is a library for handling OpenGL function pointer management for you

Epoxy is a library for handling OpenGL function pointer management for you. It hides the complexity of dlopen(), dlsym(), glXGetProcAddress(), eglGetP

Eric Anholt 553 Aug 1, 2022
Epoxy is a library for handling OpenGL function pointer management for you

Epoxy is a library for handling OpenGL function pointer management for you. It hides the complexity of dlopen(), dlsym(), glXGetProcAddress(), eglGetP

Eric Anholt 551 Jul 29, 2022
Dear IMGUI + Render + Window handling, amalgamation in two files ready to use

imgui-app Imgui-app is an amalgamation of two amazing projects Dear Imgui and Sokol libraries into two files to make it very easy to start working wit

PpluX 113 Jul 13, 2022
Handling C++ & __try exceptions without the need of built-in handlers.

manual_exception_handling this handles exceptions inside the module its specified to manage without needing previous handlers for the exception a good

null 36 Aug 8, 2022
Python envelope for the popular C library libjpeg for handling JPEG files.

jpeglib Python envelope for the popular C library libjpeg for handling JPEG files. libjpeg offers full control over compression and decompression and

Martin Benes 3 Aug 4, 2022
A simple SIP server (proxy) for handling VoIP calls based on SIP using C++

Sip Server A simple sip server for handling VoIP calls based on sip protocol. Features Registration Of Users The server supports registration process.

null 7 May 27, 2022
A forward proxy module for CONNECT request handling

name This module provides support for the CONNECT method request. This method is mainly used to tunnel SSL requests through proxy servers. Table of Co

Xiaochen Wang 1.2k Aug 8, 2022
A template C project using CMAKE, logging library and basic memory handling.

C Project template Aim of this Repository is to create a template repository for C executable projects with following properties: Cmake project Loggin

Aditya Singh Rathore 6 May 23, 2022
Wayfire plugin for handling touchpad gestures globally in a layer-shell surface

wf-globalgestures Global touchpad gestures plugin for Wayfire: implements a special protocol (also in this repo) that lets clients request that a part

null 4 Jan 18, 2022
C++14 asynchronous allocation aware futures (supporting then, exception handling, coroutines and connections)

Continuable is a C++14 library that provides full support for: lazy async continuation chaining based on callbacks (then) and expression templates, ca

Denis Blank 757 Aug 5, 2022
hotpatching, closures, lambdas, and signal-based exception handling in GNU C

Handy Headers GCC/clang is required for all headers exception.h try/except blocks in C Works with actual signals int main(){ int e; try{ //brackets

null 4 May 28, 2022
A simple header-only C++ argument parser library. Supposed to be flexible and powerful, and attempts to be compatible with the functionality of the Python standard argparse library (though not necessarily the API).

args Note that this library is essentially in maintenance mode. I haven't had the time to work on it or give it the love that it deserves. I'm not add

Taylor C. Richberger 992 Aug 5, 2022
STL compatible C++ memory allocator library using a new RawAllocator concept that is similar to an Allocator but easier to use and write.

memory The C++ STL allocator model has various flaws. For example, they are fixed to a certain type, because they are almost necessarily required to b

Jonathan Müller 1.1k Aug 4, 2022