Header file status_code.hpp

#include "status_code_domain.hpp"

namespace system_error2
{
    using in_place_t = std::in_place_t;
}

namespace system_error2
{
    namespace mixins
    {
        template <class Base, class T>
        struct mixin;
    }

    template <class ErasedType, typename std::enable_if<traits::is_move_bitcopying<ErasedType>::value, bool>::type = true>
    struct erased;

    template <class Enum>
    struct quick_status_code_from_enum;

    template <class T>
    struct is_status_code;

    template <>
    class status_code<void>;

    template <class DomainType>
    class status_code;

    namespace traits
    {
        template <class DomainType>
        struct is_move_bitcopying<status_code<DomainType>;
    }

    namespace traits
    {
    }
}

Namespace mixins

namespace mixins
{
    template <class Base, class T>
    struct mixin;
}

Namespace for user injected mixins


Struct system_error2::erased

template <class ErasedType, typename std::enable_if<traits::is_move_bitcopying<ErasedType>::value, bool>::type = true>
struct erased
{
    using value_type = ErasedType;
};

A tag for an erased value type for status_code<D>.

Available only if ErasedType satisfies traits::is_move_bitcopying<ErasedType>::value.


Struct system_error2::quick_status_code_from_enum

template <class Enum>
struct quick_status_code_from_enum;

Specialise this template to quickly wrap a third party enumeration into a custom status code domain.

Use like this:

SYSTEM_ERROR2_NAMESPACE_BEGIN
template <> struct quick_status_code_from_enum<AnotherCode> : quick_status_code_from_enum_defaults<AnotherCode>
{
  // Text name of the enum
  static constexpr const auto domain_name = "Another Code";
  // Unique UUID for the enum. PLEASE use https://www.random.org/cgi-bin/randbyte?nbytes=16&format=h
  static constexpr const auto domain_uuid = "{be201f65-3962-dd0e-1266-a72e63776a42}";
  // Map of each enum value to its text string, and list of semantically equivalent errc's
  static const std::initializer_list<mapping> &value_mappings()
  {
    static const std::initializer_list<mapping<AnotherCode>> v = {
    // Format is: { enum value, "string representation", { list of errc mappings ... } }
    {AnotherCode::success1, "Success 1", {errc::success}},        //
    {AnotherCode::goaway, "Go away", {errc::permission_denied}},  //
    {AnotherCode::success2, "Success 2", {errc::success}},        //
    {AnotherCode::error2, "Error 2", {}},                         //
    };
    return v;
  }
  // Completely optional definition of mixin for the status code synthesised from `Enum`. It can be omitted.
  template <class Base> struct mixin : Base
  {
    using Base::Base;
    constexpr int custom_method() const { return 42; }
  };
};
SYSTEM_ERROR2_NAMESPACE_END

Note that if the errc mapping contains errc::success, then the enumeration value is considered to be a successful value. Otherwise it is considered to be a failure value.

The first value in the errc mapping is the one chosen as the generic_code conversion. Other values are used during equivalence comparisons.


Struct system_error2::is_status_code

template <class T>
struct is_status_code
{
    static constexpr bool const value;
};

Trait returning true if the type is a status code.


Class system_error2::status_code

template <>
class status_code<void>
{
public:
    using domain_type = void;

    using value_type = void;

    using string_ref = typename status_code_domain::string_ref;

protected:
    system_error2::status_code_domain const* _domain;

    status_code() = default;

    status_code(system_error2::status_code<void> const&) = default;

    status_code(system_error2::status_code<void>&&) = default;

    system_error2::status_code<void>& operator=(system_error2::status_code<void> const&) = default;

    system_error2::status_code<void>& operator=(system_error2::status_code<void>&&) = default;

    ~status_code() = default;

    constexpr status_code(system_error2::status_code_domain const* v) noexcept;

public:
    constexpr system_error2::status_code_domain const& domain() const noexcept;

    constexpr bool empty() const noexcept;

    string_ref message() const noexcept;

    bool success() const noexcept;

    bool failure() const noexcept;

    template <class T>
    bool strictly_equivalent(status_code<T> const& o) const noexcept;

    template <class T>
    bool equivalent(status_code<T> const& o) const noexcept;

    void throw_exception() const;
};

A type erased lightweight status code reflecting empty, success, or failure.

Differs from status_code<erased<>> by being always available irrespective of the domain’s value type, but cannot be copied, moved, nor destructed. Thus one always passes this around by const lvalue reference.

Type alias system_error2::status_code::domain_type

using domain_type = void;

The type of the domain.


Type alias system_error2::status_code::value_type

using value_type = void;

The type of the status code.


Type alias system_error2::status_code::string_ref

using string_ref = typename status_code_domain::string_ref;

The type of a reference to a message string.


Constructor system_error2::status_code::status_code

status_code() = default;

No default construction at type erased level


Constructor system_error2::status_code::status_code

status_code(system_error2::status_code<void> const&) = default;

No public copying at type erased level


Constructor system_error2::status_code::status_code

status_code(system_error2::status_code<void>&&) = default;

No public moving at type erased level


Function system_error2::status_code::operator=

system_error2::status_code<void>& operator=(system_error2::status_code<void> const&) = default;

No public assignment at type erased level


Function system_error2::status_code::operator=

system_error2::status_code<void>& operator=(system_error2::status_code<void>&&) = default;

No public assignment at type erased level


Destructor system_error2::status_code::~status_code

~status_code() = default;

No public destruction at type erased level


Constructor system_error2::status_code::status_code

constexpr status_code(system_error2::status_code_domain const* v) noexcept;

Used to construct a non-empty type erased status code


Function system_error2::status_code::domain

constexpr system_error2::status_code_domain const& domain() const noexcept;

Return the status code domain.


Function system_error2::status_code::empty

constexpr bool empty() const noexcept;

True if the status code is empty.


Function system_error2::status_code::message

string_ref message() const noexcept;

Return a reference to a string textually representing a code.


Function system_error2::status_code::success

bool success() const noexcept;

True if code means success.


Function system_error2::status_code::failure

bool failure() const noexcept;

True if code means failure.


Function system_error2::status_code::strictly_equivalent

template <class T>
bool strictly_equivalent(status_code<T> const& o) const noexcept;

True if code is strictly (and potentially non-transitively) semantically equivalent to another code in another domain.

Note that usually non-semantic i.e. pure value comparison is used when the other status code has the same domain. As equivalent() will try mapping to generic code, this usually captures when two codes have the same semantic meaning in equivalent().


Function system_error2::status_code::equivalent

template <class T>
bool equivalent(status_code<T> const& o) const noexcept;

True if code is equivalent, by any means, to another code in another domain (guaranteed transitive).

Firstly strictly_equivalent() is run in both directions. If neither succeeds, each domain is asked for the equivalent generic code and those are compared.


Function system_error2::status_code::throw_exception

void throw_exception() const;

Throw a code as a C++ exception.



Class system_error2::status_code

template <class DomainType>
class status_code
: public mixins::mixin<detail::status_code_storage<DomainType>,DomainType>
{
public:
    using domain_type = DomainType;

    using value_type = typename domain_type::value_type;

    using string_ref = typename domain_type::string_ref;

    status_code() = default;

    status_code(const status_code<DomainType>&) = default;

    status_code(status_code<DomainType>&&) = default;

    status_code<DomainType>& operator=(const status_code<DomainType>&) = default;

    status_code<DomainType>& operator=(status_code<DomainType>&&) = default;

    ~status_code() = default;

    constexpr status_code<DomainType> clone() const;
};

A lightweight, typed, status code reflecting empty, success, or failure.

This is the main workhorse of the system_error2 library. Its characteristics reflect the value type set by its domain type, so if that value type is move-only or trivial, so is this.

An ADL discovered helper function make_status_code(T, Args...) is looked up by one of the constructors. If it is found, and it generates a status code compatible with this status code, implicit construction is made available.

You may mix in custom member functions and member function overrides by injecting a specialisation of mixins::mixin<Base, YourDomainType>. Your mixin must inherit from Base.

Type alias system_error2::status_code::domain_type

using domain_type = DomainType;

The type of the domain.


Type alias system_error2::status_code::value_type

using value_type = typename domain_type::value_type;

The type of the status code.


Type alias system_error2::status_code::string_ref

using string_ref = typename domain_type::string_ref;

The type of a reference to a message string.


Constructor system_error2::status_code::status_code

status_code() = default;

Default construction to empty


Constructor system_error2::status_code::status_code

status_code(const status_code<DomainType>&) = default;

Copy constructor


Constructor system_error2::status_code::status_code

status_code(status_code<DomainType>&&) = default;

Move constructor


Function system_error2::status_code::operator=

status_code<DomainType>& operator=(const status_code<DomainType>&) = default;

Copy assignment


Function system_error2::status_code::operator=

status_code<DomainType>& operator=(status_code<DomainType>&&) = default;

Move assignment


Function system_error2::status_code::clone

constexpr status_code<DomainType> clone() const;

Return a copy of the code.