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
{
}
}
mixins
namespace mixins
{
template <class Base, class T>
struct mixin;
}
Namespace for user injected mixins
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
.
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.
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.
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.
system_error2::status_code::domain_type
using domain_type = void;
The type of the domain.
system_error2::status_code::value_type
using value_type = void;
The type of the status code.
system_error2::status_code::string_ref
using string_ref = typename status_code_domain::string_ref;
The type of a reference to a message string.
system_error2::status_code::status_code
status_code() = default;
No default construction at type erased level
system_error2::status_code::status_code
status_code(system_error2::status_code<void> const&) = default;
No public copying at type erased level
system_error2::status_code::status_code
status_code(system_error2::status_code<void>&&) = default;
No public moving at type erased level
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
system_error2::status_code::operator=
system_error2::status_code<void>& operator=(system_error2::status_code<void>&&) = default;
No public assignment at type erased level
system_error2::status_code::~status_code
~status_code() = default;
No public destruction at type erased level
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
system_error2::status_code::domain
constexpr system_error2::status_code_domain const& domain() const noexcept;
Return the status code domain.
system_error2::status_code::empty
constexpr bool empty() const noexcept;
True if the status code is empty.
system_error2::status_code::message
string_ref message() const noexcept;
Return a reference to a string textually representing a code.
system_error2::status_code::success
bool success() const noexcept;
True if code means success.
system_error2::status_code::failure
bool failure() const noexcept;
True if code means failure.
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()
.
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.
system_error2::status_code::throw_exception
void throw_exception() const;
Throw a code as a C++ exception.
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
.
system_error2::status_code::domain_type
using domain_type = DomainType;
The type of the domain.
system_error2::status_code::value_type
using value_type = typename domain_type::value_type;
The type of the status code.
system_error2::status_code::string_ref
using string_ref = typename domain_type::string_ref;
The type of a reference to a message string.
system_error2::status_code::status_code
status_code() = default;
Default construction to empty
system_error2::status_code::status_code
status_code(const status_code<DomainType>&) = default;
Copy constructor
system_error2::status_code::status_code
status_code(status_code<DomainType>&&) = default;
Move constructor
system_error2::status_code::operator=
status_code<DomainType>& operator=(const status_code<DomainType>&) = default;
Copy assignment
system_error2::status_code::operator=
status_code<DomainType>& operator=(status_code<DomainType>&&) = default;
Move assignment
system_error2::status_code::clone
constexpr status_code<DomainType> clone() const;
Return a copy of the code.