/** * @file expected.hpp * @author Felix Morgner (felix.morgner@gmail.com) * @since 1.0.0 */ #ifndef WANDA_EXPECTED_HPP #define WANDA_EXPECTED_HPP #include #include #include namespace wanda { /** * @brief A type to represent the error case of a computation based on #wanda::expected */ template struct unexpected { static_assert(!std::is_same_v, "ErrorType can not be 'void'!"); static_assert(!std::is_array_v, "ErrorType can not be an array type!"); /** * @brief Copy construct a new @p unexpected from another @p unexpected */ constexpr unexpected(unexpected const &) = default; /** * @brief Move construct a new @p unexpected from another @p unexpected */ constexpr unexpected(unexpected &&) = default; /** * @brief Construct a new @p unexpected by direct initializing the error object from @p args */ template constexpr explicit unexpected(std::in_place_t, Args &&... args) : m_error(std::forward(args)...) { } /** * @brief Construct a new @p unexpected by direct initializing the error object from @p il and @p args */ template< typename U, typename... Args, std::enable_if_t, Args...>> * = nullptr> constexpr explicit unexpected(std::in_place_t, std::initializer_list il, Args &&... args) : m_error(il, std::forward(args)...) { } /** * @brief Construct a new @p unexpected by direct initializing the error object from @p error */ template< typename Err = ErrorType, std::enable_if_t && !std::is_same_v>, std::in_place_t> && !std::is_same_v>, unexpected>> * = nullptr> constexpr explicit unexpected(Err && error) : m_error(std::forward(error)) { } /** * @brief Construct a new @p unexpected by copying the value of another @p unexpected of different error type */ template< typename Err, std::enable_if_t && !std::is_constructible_v &> && !std::is_constructible_v> && !std::is_constructible_v const &> && !std::is_constructible_v const> && !std::is_convertible_v &, ErrorType> && !std::is_convertible_v, ErrorType> && !std::is_convertible_v const &, ErrorType> && !std::is_convertible_v const, ErrorType>)> * = nullptr, std::enable_if_t> * = nullptr> constexpr explicit unexpected(unexpected const & error) : m_error(error.m_error) { } /** * @brief Construct a new @p unexpected by copying the value of another @p unexpected of different error type */ template< typename Err, std::enable_if_t && !std::is_constructible_v &> && !std::is_constructible_v> && !std::is_constructible_v const &> && !std::is_constructible_v const> && !std::is_convertible_v &, ErrorType> && !std::is_convertible_v, ErrorType> && !std::is_convertible_v const &, ErrorType> && !std::is_convertible_v const, ErrorType>)> * = nullptr, std::enable_if_t> * = nullptr> constexpr unexpected(unexpected const & error) : m_error(error.m_error) { } /** * @brief Construct a new @p unexpected by moving the value of another @p unexpected of different error type */ template< typename Err, std::enable_if_t && !std::is_constructible_v &> && !std::is_constructible_v> && !std::is_constructible_v const &> && !std::is_constructible_v const> && !std::is_convertible_v &, ErrorType> && !std::is_convertible_v, ErrorType> && !std::is_convertible_v const &, ErrorType> && !std::is_convertible_v const, ErrorType>)> * = nullptr, std::enable_if_t> * = nullptr> constexpr explicit unexpected(unexpected && error) : m_error(std::move(error.m_error)) { } /** * @brief Construct a new @p unexpected by moving the value of another @p unexpected of different error type */ template< typename Err, std::enable_if_t && !std::is_constructible_v &> && !std::is_constructible_v> && !std::is_constructible_v const &> && !std::is_constructible_v const> && !std::is_convertible_v &, ErrorType> && !std::is_convertible_v, ErrorType> && !std::is_convertible_v const &, ErrorType> && !std::is_convertible_v const, ErrorType>)> * = nullptr, std::enable_if_t> * = nullptr> constexpr unexpected(unexpected && error) : m_error(std::move(error.m_error)) { } /** * @brief Get the error value contained in this @p unexpected instance */ constexpr ErrorType const & value() const & { return m_error; } /** * @brief Get the error value contained in this @p unexpected instance */ constexpr ErrorType & value() & { return m_error; } /** * @brief Get the error value contained in this @p unexpected instance */ constexpr ErrorType && value() && { return std::move(m_error); } /** * @brief Get the error value contained in this @p unexpected instance */ constexpr ErrorType const && value() const && { return std::move(m_error); } /** * @brief Swap the error value of this @p unexpected instance with the one of @p other */ void swap(unexpected & other) noexcept(std::is_nothrow_swappable_v) { using std::swap; swap(m_error, other.m_error); } template friend constexpr bool operator==(unexpected const & lhs, unexpected const & rhs); template friend constexpr bool operator!=(unexpected const & lhs, unexpected const & rhs); template< typename Err, std::enable_if_t> *> friend void swap(unexpected & lhs, unexpected & rhs); private: ErrorType m_error; }; template unexpected(ErrorType)->unexpected; /** * @brief Compare two @p unexpected instances for equality */ template constexpr bool operator==(unexpected const & lhs, unexpected const & rhs) { return lhs.m_error == rhs.m_error; } /** * @brief Compare two @p unexpected instances for inequality */ template constexpr bool operator!=(unexpected const & lhs, unexpected const & rhs) { return lhs.m_error != rhs.m_error; } /** * @brief Swap the error values of two @p unexpected instances */ template< typename Err, std::enable_if_t> * = nullptr> void swap(unexpected & lhs, unexpected & rhs) { lhs.swap(rhs); } /** * @brief A tag type for @p unexpected */ struct unexpect_t { explicit unexpect_t() = default; }; /** * @brief A tap for @p unexpected */ inline constexpr unexpect_t unexpect{}; } // namespace wanda #endif