#ifndef WANDA_EXPECTED_HPP #define WANDA_EXPECTED_HPP #include #include #include namespace wanda { 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