mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-14 14:56:47 +00:00
[libc++] Implement P2505R5(Monadic operations for std::expected).
Signed-off-by: yronglin <yronglin777@gmail.com>
This commit is contained in:
parent
7f3047219c
commit
ebc111b08b
@ -320,7 +320,7 @@ Status
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_constexpr_typeinfo`` ``202106L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_expected`` ``202202L``
|
||||
``__cpp_lib_expected`` ``202211L``
|
||||
------------------------------------------------- -----------------
|
||||
``__cpp_lib_format_ranges`` ``202207L``
|
||||
------------------------------------------------- -----------------
|
||||
|
@ -41,6 +41,7 @@ Implemented Papers
|
||||
- P1328R1 - ``constexpr type_info::operator==()``
|
||||
- P1413R3 - Formatting ``thread::id`` (the ``stacktrace`` is not done yet)
|
||||
- P2675R1 - ``format``'s width estimation is too approximate and not forward compatible
|
||||
- P2505R5 - Monadic operations for ``std::expected``
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
@ -274,7 +274,7 @@
|
||||
"`3853 <https://wg21.link/LWG3853>`__","``basic_const_iterator<volatile int*>::operator->`` is ill-formed","February 2023","","",""
|
||||
"`3857 <https://wg21.link/LWG3857>`__","``basic_string_view`` should allow explicit conversion when only traits vary","February 2023","|Complete|","17.0",""
|
||||
"`3860 <https://wg21.link/LWG3860>`__","``range_common_reference_t`` is missing","February 2023","|Complete|","17.0","|ranges|"
|
||||
"`3866 <https://wg21.link/LWG3866>`__","Bad Mandates for ``expected::transform_error`` overloads","February 2023","","",""
|
||||
"`3866 <https://wg21.link/LWG3866>`__","Bad Mandates for ``expected::transform_error`` overloads","February 2023","|Complete|","17.0",""
|
||||
"`3867 <https://wg21.link/LWG3867>`__","Should ``std::basic_osyncstream``'s move assignment operator be ``noexcept``?","February 2023","","",""
|
||||
"`3441 <https://wg21.link/LWG3441>`__","Misleading note about calls to customization points","February 2023","","",""
|
||||
"`3622 <https://wg21.link/LWG3622>`__","Misspecified transitivity of equivalence in §[unord.req.general]","February 2023","","",""
|
||||
@ -301,7 +301,7 @@
|
||||
"`3872 <https://wg21.link/LWG3872>`__","``basic_const_iterator`` should have custom ``iter_move``","February 2023","","",""
|
||||
"`3875 <https://wg21.link/LWG3875>`__","``std::ranges::repeat_view<T, IntegerClass>::iterator`` may be ill-formed","February 2023","","","|ranges|"
|
||||
"`3876 <https://wg21.link/LWG3876>`__","Default constructor of ``std::layout_XX::mapping`` misses precondition","February 2023","","",""
|
||||
"`3877 <https://wg21.link/LWG3877>`__","Incorrect constraints on ``const``-qualified monadic overloads for ``std::expected``","February 2023","","",""
|
||||
"`3877 <https://wg21.link/LWG3877>`__","Incorrect constraints on ``const``-qualified monadic overloads for ``std::expected``","February 2023","|Complete|","17.0",""
|
||||
"`3878 <https://wg21.link/LWG3878>`__","import ``std;`` should guarantee initialization of standard iostreams objects","February 2023","","",""
|
||||
"`3879 <https://wg21.link/LWG3879>`__","``erase_if`` for ``flat_{,multi}set`` is incorrectly specified","February 2023","","",""
|
||||
"`3880 <https://wg21.link/LWG3880>`__","Clarify ``operator+=`` complexity for ``{chunk,stride}_view::iterator``","February 2023","","","|ranges|"
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -100,7 +100,7 @@
|
||||
"`P1478R8 <https://wg21.link/P1478R8>`__","LWG", "``Byte-wise`` ``atomic`` ``memcpy``", "November 2022","","","|concurrency TS|"
|
||||
"`P2167R3 <https://wg21.link/P2167R3>`__","LWG", "Improved Proposed Wording for LWG 2114", "November 2022","","",""
|
||||
"`P2396R1 <https://wg21.link/P2396R1>`__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|"
|
||||
"`P2505R5 <https://wg21.link/P2505R5>`__","LWG", "Monadic Functions for ``std::expected``", "November 2022","","",""
|
||||
"`P2505R5 <https://wg21.link/P2505R5>`__","LWG", "Monadic Functions for ``std::expected``", "November 2022","|Complete|","17.0",""
|
||||
"`P2539R4 <https://wg21.link/P2539R4>`__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","","","|format|"
|
||||
"`P2602R2 <https://wg21.link/P2602R2>`__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|"
|
||||
"`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","",""
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
@ -14,10 +14,12 @@
|
||||
#include <__expected/bad_expected_access.h>
|
||||
#include <__expected/unexpect.h>
|
||||
#include <__expected/unexpected.h>
|
||||
#include <__functional/invoke.h>
|
||||
#include <__memory/addressof.h>
|
||||
#include <__memory/construct_at.h>
|
||||
#include <__type_traits/conjunction.h>
|
||||
#include <__type_traits/disjunction.h>
|
||||
#include <__type_traits/integral_constant.h>
|
||||
#include <__type_traits/is_assignable.h>
|
||||
#include <__type_traits/is_constructible.h>
|
||||
#include <__type_traits/is_convertible.h>
|
||||
@ -60,7 +62,17 @@
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
namespace __expected {
|
||||
template <class _Tp, class _Err>
|
||||
class expected;
|
||||
|
||||
template <class _Tp>
|
||||
struct __is_std_expected : false_type {};
|
||||
|
||||
template <class _Tp, class _Err>
|
||||
struct __is_std_expected<expected<_Tp, _Err>> : true_type {};
|
||||
|
||||
struct __expected_construct_in_place_from_invoke_tag {};
|
||||
struct __expected_construct_unexpected_from_invoke_tag {};
|
||||
|
||||
template <class _Err, class _Arg>
|
||||
_LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
|
||||
@ -72,8 +84,6 @@ _LIBCPP_HIDE_FROM_ABI void __throw_bad_expected_access(_Arg&& __arg) {
|
||||
# endif
|
||||
}
|
||||
|
||||
} // namespace __expected
|
||||
|
||||
template <class _Tp, class _Err>
|
||||
class expected {
|
||||
static_assert(
|
||||
@ -166,6 +176,15 @@ private:
|
||||
_Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>&>>,
|
||||
_Not<is_constructible<unexpected<_Err>, const expected<_Up, _OtherErr>>> >;
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
|
||||
std::__expected_construct_in_place_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
|
||||
: __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(true) {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
|
||||
std::__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
|
||||
: __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {}
|
||||
|
||||
public:
|
||||
template <class _Up, class _OtherErr>
|
||||
@ -538,28 +557,28 @@ public:
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& {
|
||||
if (!__has_val_) {
|
||||
__expected::__throw_bad_expected_access<_Err>(__union_.__unex_);
|
||||
std::__throw_bad_expected_access<_Err>(__union_.__unex_);
|
||||
}
|
||||
return __union_.__val_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
|
||||
if (!__has_val_) {
|
||||
__expected::__throw_bad_expected_access<_Err>(__union_.__unex_);
|
||||
std::__throw_bad_expected_access<_Err>(__union_.__unex_);
|
||||
}
|
||||
return __union_.__val_;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& {
|
||||
if (!__has_val_) {
|
||||
__expected::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
|
||||
std::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
|
||||
}
|
||||
return std::move(__union_.__val_);
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
|
||||
if (!__has_val_) {
|
||||
__expected::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
|
||||
std::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
|
||||
}
|
||||
return std::move(__union_.__val_);
|
||||
}
|
||||
@ -598,6 +617,245 @@ public:
|
||||
return __has_val_ ? std::move(__union_.__val_) : static_cast<_Tp>(std::forward<_Up>(__v));
|
||||
}
|
||||
|
||||
template <class _Up = _Err>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
|
||||
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
|
||||
static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
|
||||
if (has_value())
|
||||
return std::forward<_Up>(__error);
|
||||
return error();
|
||||
}
|
||||
|
||||
template <class _Up = _Err>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && {
|
||||
static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible");
|
||||
static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
|
||||
if (has_value())
|
||||
return std::forward<_Up>(__error);
|
||||
return std::move(error());
|
||||
}
|
||||
|
||||
// [expected.void.monadic], monadic
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&>>;
|
||||
static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Up::error_type, _Err>,
|
||||
"The result of f(value()) must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f), value());
|
||||
}
|
||||
return _Up(unexpect, error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&>>;
|
||||
static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Up::error_type, _Err>,
|
||||
"The result of f(value()) must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f), value());
|
||||
}
|
||||
return _Up(unexpect, error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&&>>;
|
||||
static_assert(
|
||||
__is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Up::error_type, _Err>,
|
||||
"The result of f(std::move(value())) must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f), std::move(value()));
|
||||
}
|
||||
return _Up(unexpect, std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>;
|
||||
static_assert(
|
||||
__is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Up::error_type, _Err>,
|
||||
"The result of f(std::move(value())) must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f), std::move(value()));
|
||||
}
|
||||
return _Up(unexpect, std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, _Tp&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>;
|
||||
static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(error()) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp(in_place, value());
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, const _Tp&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>;
|
||||
static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(error()) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp(in_place, value());
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, _Tp&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>;
|
||||
static_assert(
|
||||
__is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(std::move(error())) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp(in_place, std::move(value()));
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, const _Tp&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>;
|
||||
static_assert(
|
||||
__is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(std::move(error())) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp(in_place, std::move(value()));
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, error());
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), value());
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f), value());
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, error());
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), value());
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f), value());
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&&>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, std::move(error()));
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(
|
||||
__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value()));
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f), std::move(value()));
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&&>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, std::move(error()));
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(
|
||||
__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f), std::move(value()));
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f), std::move(value()));
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, _Tp&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(error()) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>(in_place, value());
|
||||
}
|
||||
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, const _Tp&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(error()) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>(in_place, value());
|
||||
}
|
||||
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, _Tp&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(std::move(error())) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>(in_place, std::move(value()));
|
||||
}
|
||||
return expected<_Tp, _Gp>(
|
||||
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Tp, const _Tp&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(std::move(error())) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>(in_place, std::move(value()));
|
||||
}
|
||||
return expected<_Tp, _Gp>(
|
||||
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
// [expected.object.eq], equality operators
|
||||
template <class _T2, class _E2>
|
||||
requires(!is_void_v<_T2>)
|
||||
@ -625,24 +883,66 @@ public:
|
||||
|
||||
private:
|
||||
struct __empty_t {};
|
||||
// use named union because [[no_unique_address]] cannot be applied to an unnamed union
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS union __union_t {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
|
||||
|
||||
template <class _ValueType, class _ErrorType>
|
||||
union __union_t {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __union_t() {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
|
||||
std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
|
||||
: __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
|
||||
std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
|
||||
: __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
|
||||
requires(is_trivially_destructible_v<_Tp> && is_trivially_destructible_v<_Err>)
|
||||
requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
|
||||
= default;
|
||||
|
||||
// the expected's destructor handles this
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
|
||||
|
||||
_ValueType __val_;
|
||||
_ErrorType __unex_;
|
||||
};
|
||||
|
||||
// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
|
||||
// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
|
||||
// it's not clear that it's implementable, given that the function is allowed to clobber
|
||||
// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
|
||||
template <class _ValueType, class _ErrorType>
|
||||
requires(is_trivially_move_constructible_v<_ValueType> && is_trivially_move_constructible_v<_ErrorType>)
|
||||
union __union_t<_ValueType, _ErrorType> {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
|
||||
std::__expected_construct_in_place_from_invoke_tag, _Func&& __f, _Args&&... __args)
|
||||
: __val_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
|
||||
std::__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
|
||||
: __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
|
||||
requires(is_trivially_destructible_v<_ValueType> && is_trivially_destructible_v<_ErrorType>)
|
||||
= default;
|
||||
|
||||
// the expected's destructor handles this
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
|
||||
requires(!is_trivially_destructible_v<_Tp> || !is_trivially_destructible_v<_Err>)
|
||||
requires(!is_trivially_destructible_v<_ValueType> || !is_trivially_destructible_v<_ErrorType>)
|
||||
{}
|
||||
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Tp __val_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
|
||||
} __union_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _ValueType __val_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
|
||||
};
|
||||
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Tp, _Err> __union_;
|
||||
bool __has_val_;
|
||||
};
|
||||
|
||||
@ -762,6 +1062,19 @@ public:
|
||||
std::construct_at(std::addressof(__union_.__unex_), __il, std::forward<_Args>(__args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(__expected_construct_in_place_from_invoke_tag, _Func&& __f)
|
||||
: __has_val_(true) {
|
||||
std::invoke(std::forward<_Func>(__f));
|
||||
}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit expected(
|
||||
__expected_construct_unexpected_from_invoke_tag __tag, _Func&& __f, _Args&&... __args)
|
||||
: __union_(__tag, std::forward<_Func>(__f), std::forward<_Args>(__args)...), __has_val_(false) {}
|
||||
|
||||
public:
|
||||
// [expected.void.dtor], destructor
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~expected()
|
||||
@ -899,13 +1212,13 @@ public:
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void value() const& {
|
||||
if (!__has_val_) {
|
||||
__expected::__throw_bad_expected_access<_Err>(__union_.__unex_);
|
||||
std::__throw_bad_expected_access<_Err>(__union_.__unex_);
|
||||
}
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr void value() && {
|
||||
if (!__has_val_) {
|
||||
__expected::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
|
||||
std::__throw_bad_expected_access<_Err>(std::move(__union_.__unex_));
|
||||
}
|
||||
}
|
||||
|
||||
@ -929,6 +1242,235 @@ public:
|
||||
return std::move(__union_.__unex_);
|
||||
}
|
||||
|
||||
template <class _Up = _Err>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& {
|
||||
static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible");
|
||||
static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
|
||||
if (has_value()) {
|
||||
return std::forward<_Up>(__error);
|
||||
}
|
||||
return error();
|
||||
}
|
||||
|
||||
template <class _Up = _Err>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && {
|
||||
static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible");
|
||||
static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type");
|
||||
if (has_value()) {
|
||||
return std::forward<_Up>(__error);
|
||||
}
|
||||
return std::move(error());
|
||||
}
|
||||
|
||||
// [expected.void.monadic], monadic
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
|
||||
static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
|
||||
static_assert(
|
||||
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f));
|
||||
}
|
||||
return _Up(unexpect, error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
|
||||
static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
|
||||
static_assert(
|
||||
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f));
|
||||
}
|
||||
return _Up(unexpect, error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
|
||||
static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
|
||||
static_assert(
|
||||
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f));
|
||||
}
|
||||
return _Up(unexpect, std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
|
||||
using _Up = remove_cvref_t<invoke_result_t<_Func>>;
|
||||
static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected");
|
||||
static_assert(
|
||||
is_same_v<typename _Up::error_type, _Err>, "The result of f() must have the same error_type as this expected");
|
||||
if (has_value()) {
|
||||
return std::invoke(std::forward<_Func>(__f));
|
||||
}
|
||||
return _Up(unexpect, std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>;
|
||||
static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(error()) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp();
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>;
|
||||
static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(error()) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp();
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>;
|
||||
static_assert(__is_std_expected<_Gp>::value,
|
||||
"The result of f(std::move(error())) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(std::move(error())) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp();
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& {
|
||||
using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>;
|
||||
static_assert(__is_std_expected<_Gp>::value,
|
||||
"The result of f(std::move(error())) must be a specialization of std::expected");
|
||||
static_assert(is_same_v<typename _Gp::value_type, _Tp>,
|
||||
"The result of f(std::move(error())) must have the same value_type as this expected");
|
||||
if (has_value()) {
|
||||
return _Gp();
|
||||
}
|
||||
return std::invoke(std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, error());
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f));
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f));
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, error());
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f));
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f));
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, std::move(error()));
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f));
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f));
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
requires is_constructible_v<_Err, const _Err&&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
|
||||
using _Up = remove_cv_t<invoke_result_t<_Func>>;
|
||||
if (!has_value()) {
|
||||
return expected<_Up, _Err>(unexpect, std::move(error()));
|
||||
}
|
||||
if constexpr (!is_void_v<_Up>) {
|
||||
return expected<_Up, _Err>(__expected_construct_in_place_from_invoke_tag{}, std::forward<_Func>(__f));
|
||||
} else {
|
||||
std::invoke(std::forward<_Func>(__f));
|
||||
return expected<_Up, _Err>();
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(error()) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>();
|
||||
}
|
||||
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(error()) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>();
|
||||
}
|
||||
return expected<_Tp, _Gp>(__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), error());
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(std::move(error())) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>();
|
||||
}
|
||||
return expected<_Tp, _Gp>(
|
||||
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
template <class _Func>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& {
|
||||
using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&&>>;
|
||||
static_assert(__valid_std_unexpected<_Gp>::value,
|
||||
"The result of f(std::move(error())) must be a valid template argument for unexpected");
|
||||
if (has_value()) {
|
||||
return expected<_Tp, _Gp>();
|
||||
}
|
||||
return expected<_Tp, _Gp>(
|
||||
__expected_construct_unexpected_from_invoke_tag{}, std::forward<_Func>(__f), std::move(error()));
|
||||
}
|
||||
|
||||
// [expected.void.eq], equality operators
|
||||
template <class _T2, class _E2>
|
||||
requires is_void_v<_T2>
|
||||
@ -947,23 +1489,55 @@ public:
|
||||
|
||||
private:
|
||||
struct __empty_t {};
|
||||
// use named union because [[no_unique_address]] cannot be applied to an unnamed union
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS union __union_t {
|
||||
|
||||
template <class _ErrorType>
|
||||
union __union_t {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
|
||||
__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
|
||||
: __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
|
||||
requires(is_trivially_destructible_v<_Err>)
|
||||
requires(is_trivially_destructible_v<_ErrorType>)
|
||||
= default;
|
||||
|
||||
// the expected's destructor handles this
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t() {}
|
||||
|
||||
__empty_t __empty_;
|
||||
_ErrorType __unex_;
|
||||
};
|
||||
|
||||
// use named union because [[no_unique_address]] cannot be applied to an unnamed union,
|
||||
// also guaranteed elision into a potentially-overlapping subobject is unsettled (and
|
||||
// it's not clear that it's implementable, given that the function is allowed to clobber
|
||||
// the tail padding) - see https://github.com/itanium-cxx-abi/cxx-abi/issues/107.
|
||||
template <class _ErrorType>
|
||||
requires is_trivially_move_constructible_v<_ErrorType>
|
||||
union __union_t<_ErrorType> {
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __union_t() : __empty_() {}
|
||||
|
||||
template <class _Func, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __union_t(
|
||||
__expected_construct_unexpected_from_invoke_tag, _Func&& __f, _Args&&... __args)
|
||||
: __unex_(std::invoke(std::forward<_Func>(__f), std::forward<_Args>(__args)...)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
|
||||
requires(is_trivially_destructible_v<_ErrorType>)
|
||||
= default;
|
||||
|
||||
// the expected's destructor handles this
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr ~__union_t()
|
||||
requires(!is_trivially_destructible_v<_Err>)
|
||||
requires(!is_trivially_destructible_v<_ErrorType>)
|
||||
{}
|
||||
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __empty_t __empty_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _Err __unex_;
|
||||
} __union_;
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS _ErrorType __unex_;
|
||||
};
|
||||
|
||||
_LIBCPP_NO_UNIQUE_ADDRESS __union_t<_Err> __union_;
|
||||
bool __has_val_;
|
||||
};
|
||||
|
||||
|
@ -82,7 +82,7 @@ __cpp_lib_erase_if 202002L <deque> <forward
|
||||
__cpp_lib_exchange_function 201304L <utility>
|
||||
__cpp_lib_execution 201902L <execution>
|
||||
201603L // C++17
|
||||
__cpp_lib_expected 202202L <expected>
|
||||
__cpp_lib_expected 202211L <expected>
|
||||
__cpp_lib_filesystem 201703L <filesystem>
|
||||
__cpp_lib_format 202106L <format>
|
||||
__cpp_lib_format_ranges 202207L <format>
|
||||
@ -399,7 +399,7 @@ __cpp_lib_void_t 201411L <type_traits>
|
||||
# undef __cpp_lib_constexpr_memory
|
||||
# define __cpp_lib_constexpr_memory 202202L
|
||||
# define __cpp_lib_constexpr_typeinfo 202106L
|
||||
# define __cpp_lib_expected 202202L
|
||||
# define __cpp_lib_expected 202211L
|
||||
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
# define __cpp_lib_format_ranges 202207L
|
||||
# endif
|
||||
|
@ -0,0 +1,126 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
// template<class F> constexpr auto and_then(F&& f) &;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) const &;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) &&;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) const &&;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F, decltype(value())>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
struct NotSameAsInt {};
|
||||
|
||||
int lval_return_not_std_expected(int&) { return 0; }
|
||||
int clval_return_not_std_expected(const int&) { return 0; }
|
||||
int rval_return_not_std_expected(int&&) { return 0; }
|
||||
int crval_return_not_std_expected(const int&&) { return 0; }
|
||||
|
||||
std::expected<int, NotSameAsInt> lval_error_type_not_same_as_int(int&) { return {}; }
|
||||
std::expected<int, NotSameAsInt> clval_error_type_not_same_as_int(const int&) { return {}; }
|
||||
std::expected<int, NotSameAsInt> rval_error_type_not_same_as_int(int&&) { return {}; }
|
||||
std::expected<int, NotSameAsInt> crval_error_type_not_same_as_int(const int&&) { return {}; }
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
// Test & overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
std::expected<int, int> f1(1);
|
||||
f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
std::expected<int, int> f1(1);
|
||||
f1.and_then(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<int, int> f1(1);
|
||||
f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(const int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
const std::expected<int, int> f1(1);
|
||||
f1.and_then(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(const int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(value()) must have the same error_type as this expected}}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
std::expected<int, int> f1(1);
|
||||
std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
std::expected<int, int> f1(1);
|
||||
std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<int, int> f1(1);
|
||||
std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<int (&)(const int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
const std::expected<int, int> f1(1);
|
||||
std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::and_then<std::expected<int, NotSameAsInt> (&)(const int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(value())) must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -0,0 +1,72 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
// template<class G = E> constexpr E error_or(G&&) const &;
|
||||
// Mandates: is_copy_constructible_v<G> is true and is_convertible_v<U, E> is true.
|
||||
|
||||
// template<class G = E> constexpr E error_or(G&&) &&;
|
||||
// Mandates: is_move_constructible_v<G> is true and is_convertible_v<U, E> is true.
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
struct NonCopyable {
|
||||
NonCopyable(int) {}
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
};
|
||||
|
||||
struct NonMovable {
|
||||
NonMovable(int) {}
|
||||
NonMovable(NonMovable&&) = delete;
|
||||
};
|
||||
|
||||
struct NotConvertibleFromInt {};
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
// const & overload
|
||||
// !is_copy_constructible_v<G>,
|
||||
{
|
||||
const std::expected<int, NonCopyable> f1(std::unexpect, 0);
|
||||
f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<int, NonCopyable>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be copy constructible}}
|
||||
// expected-error-re@*:* {{call to deleted constructor of{{.*}}}}
|
||||
}
|
||||
|
||||
// const & overload
|
||||
// !is_convertible_v<U, T>
|
||||
{
|
||||
const std::expected<int, NotConvertibleFromInt> f1(std::unexpect, NotConvertibleFromInt{});
|
||||
f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<int, NotConvertibleFromInt>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}}
|
||||
// expected-error-re@*:* {{no viable conversion from returned value of type{{.*}}}}
|
||||
|
||||
}
|
||||
|
||||
// && overload
|
||||
// !is_move_constructible_v<T>,
|
||||
{
|
||||
std::expected<int, NonMovable> f1(std::unexpect, 0);
|
||||
std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<int, NonMovable>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be move constructible}}
|
||||
// expected-error-re@*:* {{call to deleted constructor of{{.*}}}}
|
||||
}
|
||||
|
||||
// && overload
|
||||
// !is_convertible_v<U, T>
|
||||
{
|
||||
std::expected<int, NotConvertibleFromInt> f1(std::unexpect, NotConvertibleFromInt{});
|
||||
std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<int, NotConvertibleFromInt>::error_or<int>' requested here}}
|
||||
//expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}}
|
||||
// expected-error-re@*:* {{no viable conversion from returned value of type{{.*}}}}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -16,4 +16,20 @@
|
||||
|
||||
struct Empty {};
|
||||
|
||||
struct A {
|
||||
int x_;
|
||||
int y_;
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
int z_;
|
||||
virtual ~B() = default;
|
||||
};
|
||||
|
||||
static_assert(sizeof(std::expected<Empty, Empty>) == sizeof(bool));
|
||||
static_assert(sizeof(std::expected<Empty, A>) == 2 * sizeof(int) + alignof(std::expected<Empty, A>));
|
||||
static_assert(sizeof(std::expected<Empty, B>) == sizeof(B) + alignof(std::expected<Empty, B>));
|
||||
static_assert(sizeof(std::expected<A, Empty>) == 2 * sizeof(int) + alignof(std::expected<A, Empty>));
|
||||
static_assert(sizeof(std::expected<A, A>) == 2 * sizeof(int) + alignof(std::expected<A, A>));
|
||||
static_assert(sizeof(std::expected<B, Empty>) == sizeof(B) + alignof(std::expected<B, Empty>));
|
||||
static_assert(sizeof(std::expected<B, B>) == sizeof(B) + alignof(std::expected<B, B>));
|
||||
|
@ -0,0 +1,125 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
// template<class F> constexpr auto or_else(F&& f) &;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) const &;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) &&;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) const &&;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
struct NotSameAsInt {};
|
||||
|
||||
int lval_return_not_std_expected(int&) { return 0; }
|
||||
int clval_return_not_std_expected(const int&) { return 0; }
|
||||
int rval_return_not_std_expected(int&&) { return 0; }
|
||||
int crval_return_not_std_expected(const int&&) { return 0; }
|
||||
|
||||
std::expected<NotSameAsInt, int> lval_error_type_not_same_as_int(int&) { return {}; }
|
||||
std::expected<NotSameAsInt, int> clval_error_type_not_same_as_int(const int&) { return {}; }
|
||||
std::expected<NotSameAsInt, int> rval_error_type_not_same_as_int(int&&) { return {}; }
|
||||
std::expected<NotSameAsInt, int> crval_error_type_not_same_as_int(const int&&) { return {}; }
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
// Test & overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(const int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
const std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<int (&)(const int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
const std::expected<int, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<int, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -0,0 +1,84 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &;
|
||||
//
|
||||
// Let G be remove_cv_t<invoke_result_t<F, decltype(error())>>
|
||||
// G is a valid template argument for unexpected ([expected.un.general]) and the declaration
|
||||
// G g(invoke(std::forward<F>(f), error())); is well-formed.
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &&;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &&;
|
||||
//
|
||||
// Let G be remove_cv_t<invoke_result_t<F, decltype(std::move(error()))>>.
|
||||
// G is a valid template argument for unexpected ([expected.un.general]) and the declaration
|
||||
// G g(invoke(std::forward<F>(f), std::move(error()))); is well-formed.
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
static int val;
|
||||
|
||||
template <class T>
|
||||
std::unexpected<int> return_unexpected(T) {
|
||||
return std::unexpected<int>(1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int& return_no_object(T) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
|
||||
// Test & overload
|
||||
{
|
||||
std::expected<int, int> e;
|
||||
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
|
||||
|
||||
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}[expected.object.general] A program that instantiates the definition of template expected<T, E> for {{.*}} is ill-formed.}}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
const std::expected<int, int> e;
|
||||
e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
std::expected<int, int> e;
|
||||
std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
const std::expected<int, int> e;
|
||||
std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* 2 {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -0,0 +1,125 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
// template<class F> constexpr auto and_then(F&& f) &;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) const &;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) &&;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) const &&;
|
||||
// Mandates:
|
||||
// Let U be std::remove_cvref_t<std::invoke_result<F>>
|
||||
// U is a specialization of std::expected and std::is_same_v<U:error_type, E> is true
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
struct NotSameAsInt {};
|
||||
|
||||
int lval_return_not_std_expected(void) { return 0; }
|
||||
int clval_return_not_std_expected(void) { return 0; }
|
||||
int rval_return_not_std_expected(void) { return 0; }
|
||||
int crval_return_not_std_expected(void) { return 0; }
|
||||
|
||||
std::expected<int, NotSameAsInt> lval_error_type_not_same_as_int(void) { return {}; }
|
||||
std::expected<int, NotSameAsInt> clval_error_type_not_same_as_int(void) { return {}; }
|
||||
std::expected<int, NotSameAsInt> rval_error_type_not_same_as_int(void) { return {}; }
|
||||
std::expected<int, NotSameAsInt> crval_error_type_not_same_as_int(void) { return {}; }
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
// Test & overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
std::expected<void, int> f1;
|
||||
f1.and_then(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
std::expected<void, int> f1;
|
||||
f1.and_then(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<void, int> f1;
|
||||
f1.and_then(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
const std::expected<void, int> f1;
|
||||
f1.and_then(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
std::expected<void, int> f1;
|
||||
std::move(f1).and_then(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
std::expected<void, int> f1;
|
||||
std::move(f1).and_then(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// U is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<void, int> f1;
|
||||
std::move(f1).and_then(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<int (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
// expected-error-re@*:* {{no matching constructor for initialization of{{.*}}}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<U:error_type, E>
|
||||
{
|
||||
const std::expected<void, int> f1;
|
||||
std::move(f1).and_then(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::and_then<std::expected<int, NotSameAsInt> (&)()>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f() must have the same error_type as this expected}}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -0,0 +1,71 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
// template<class G = E> constexpr E error_or(G&&) const &;
|
||||
// Mandates: is_copy_constructible_v<G> is true and is_convertible_v<U, E> is true.
|
||||
|
||||
// template<class G = E> constexpr E error_or(G&&) &&;
|
||||
// Mandates: is_move_constructible_v<G> is true and is_convertible_v<U, E> is true.
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
struct NonCopyable {
|
||||
NonCopyable(int) {}
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
};
|
||||
|
||||
struct NonMovable {
|
||||
NonMovable(int) {}
|
||||
NonMovable(NonMovable&&) = delete;
|
||||
};
|
||||
|
||||
struct NotConvertibleFromInt {};
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
// const & overload
|
||||
// !is_copy_constructible_v<G>,
|
||||
{
|
||||
const std::expected<void, NonCopyable> f1(std::unexpect, 0);
|
||||
f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<void, NonCopyable>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be copy constructible}}
|
||||
// expected-error-re@*:* {{call to deleted constructor of{{.*}}}}
|
||||
}
|
||||
|
||||
// const & overload
|
||||
// !is_convertible_v<U, T>
|
||||
{
|
||||
const std::expected<void, NotConvertibleFromInt> f1(std::unexpect, NotConvertibleFromInt{});
|
||||
f1.error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<void, NotConvertibleFromInt>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}}
|
||||
// expected-error-re@*:* {{no viable conversion from returned value of type{{.*}}}}
|
||||
}
|
||||
|
||||
// && overload
|
||||
// !is_move_constructible_v<T>,
|
||||
{
|
||||
std::expected<void, NonMovable> f1(std::unexpect, 0);
|
||||
std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<void, NonMovable>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}error_type has to be move constructible}}
|
||||
// expected-error-re@*:* {{call to deleted constructor of{{.*}}}}
|
||||
}
|
||||
|
||||
// && overload
|
||||
// !is_convertible_v<U, T>
|
||||
{
|
||||
std::expected<void, NotConvertibleFromInt> f1(std::unexpect, NotConvertibleFromInt{});
|
||||
std::move(f1).error_or(5); // expected-note{{in instantiation of function template specialization 'std::expected<void, NotConvertibleFromInt>::error_or<int>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}argument has to be convertible to error_type}}
|
||||
// expected-error-re@*:* {{no viable conversion from returned value of type{{.*}}}}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -16,4 +16,16 @@
|
||||
|
||||
struct Empty {};
|
||||
|
||||
struct A {
|
||||
int x_;
|
||||
int y_;
|
||||
};
|
||||
|
||||
struct B : public A {
|
||||
int z_;
|
||||
virtual ~B() = default;
|
||||
};
|
||||
|
||||
static_assert(sizeof(std::expected<void, Empty>) == sizeof(bool));
|
||||
static_assert(sizeof(std::expected<void, A>) == 2 * sizeof(int) + alignof(std::expected<void, A>));
|
||||
static_assert(sizeof(std::expected<void, B>) == sizeof(B) + alignof(std::expected<void, B>));
|
||||
|
@ -0,0 +1,121 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
// template<class F> constexpr auto or_else(F&& f) &;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) const &;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) &&;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) const &&;
|
||||
// Mandates:
|
||||
// Let G be std::remove_cvref_t<std::invoke_result<F, decltype(error())>>
|
||||
// G is a specialization of std::expected and std::is_same_v<G:value_type, T> is true
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
struct NotSameAsInt {};
|
||||
|
||||
int lval_return_not_std_expected(int&) { return 0; }
|
||||
int clval_return_not_std_expected(const int&) { return 0; }
|
||||
int rval_return_not_std_expected(int&&) { return 0; }
|
||||
int crval_return_not_std_expected(const int&&) { return 0; }
|
||||
|
||||
std::expected<NotSameAsInt, int> lval_error_type_not_same_as_int(int&) { return {}; }
|
||||
std::expected<NotSameAsInt, int> clval_error_type_not_same_as_int(const int&) { return {}; }
|
||||
std::expected<NotSameAsInt, int> rval_error_type_not_same_as_int(int&&) { return {}; }
|
||||
std::expected<NotSameAsInt, int> crval_error_type_not_same_as_int(const int&&) { return {}; }
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
// Test & overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(lval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(lval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(clval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(const int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
const std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
f1.or_else(clval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(error()) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(rval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(rval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// G is not a specialization of std::expected
|
||||
{
|
||||
const std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(crval_return_not_std_expected); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<int (&)(const int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must be a specialization of std::expected}}
|
||||
// expected-error-re@*:* {{{{.*}}cannot be used prior to '::' because it has no members}}
|
||||
}
|
||||
|
||||
// !std::is_same_v<G:value_type, T>
|
||||
{
|
||||
const std::expected<void, int> f1(std::unexpected<int>(1));
|
||||
std::move(f1).or_else(crval_error_type_not_same_as_int); // expected-note{{in instantiation of function template specialization 'std::expected<void, int>::or_else<std::expected<NotSameAsInt, int> (&)(const int &&)>' requested here}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of f(std::move(error())) must have the same value_type as this expected}}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -0,0 +1,84 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// Test the mandates
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &;
|
||||
//
|
||||
// Let G be remove_cv_t<invoke_result_t<F, decltype(error())>>
|
||||
// G is a valid template argument for unexpected ([expected.un.general]) and the declaration
|
||||
// G g(invoke(std::forward<F>(f), error())); is well-formed.
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &&;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &&;
|
||||
//
|
||||
// Let G be remove_cv_t<invoke_result_t<F, decltype(std::move(error()))>>.
|
||||
// G is a valid template argument for unexpected ([expected.un.general]) and the declaration
|
||||
// G g(invoke(std::forward<F>(f), std::move(error()))); is well-formed.
|
||||
|
||||
#include <expected>
|
||||
#include <utility>
|
||||
|
||||
static int val;
|
||||
|
||||
template <class T>
|
||||
std::unexpected<int> return_unexpected(T) {
|
||||
return std::unexpected<int>(1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int& return_no_object(T) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
void test() {
|
||||
|
||||
// Test & overload
|
||||
{
|
||||
std::expected<void, int> e;
|
||||
e.transform_error(return_unexpected<int&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
|
||||
|
||||
e.transform_error(return_no_object<int&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
// expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}A program that instantiates expected<T, E> with a E that is not a valid argument for unexpected<E> is ill-formed}}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
const std::expected<void, int> e;
|
||||
e.transform_error(return_unexpected<const int &>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
e.transform_error(return_no_object<const int &>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
std::expected<void, int> e;
|
||||
std::move(e).transform_error(return_unexpected<int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
std::move(e).transform_error(return_no_object<int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
const std::expected<void, int> e;
|
||||
std::move(e).transform_error(return_unexpected<const int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
std::move(e).transform_error(return_no_object<const int&&>); // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}The result of {{.*}} must be a valid template argument for unexpected}}
|
||||
// expected-error-re@*:* {{{{(excess elements in struct initializer|no matching constructor for initialization of)}}{{.*}}}}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
@ -16,7 +16,7 @@
|
||||
// Test the feature test macros defined by <expected>
|
||||
|
||||
/* Constant Value
|
||||
__cpp_lib_expected 202202L [C++2b]
|
||||
__cpp_lib_expected 202211L [C++2b]
|
||||
*/
|
||||
|
||||
#include <expected>
|
||||
@ -51,8 +51,8 @@
|
||||
# ifndef __cpp_lib_expected
|
||||
# error "__cpp_lib_expected should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_expected != 202202L
|
||||
# error "__cpp_lib_expected should have the value 202202L in c++2b"
|
||||
# if __cpp_lib_expected != 202211L
|
||||
# error "__cpp_lib_expected should have the value 202211L in c++2b"
|
||||
# endif
|
||||
|
||||
#endif // TEST_STD_VER > 20
|
||||
|
@ -76,7 +76,7 @@
|
||||
__cpp_lib_exchange_function 201304L [C++14]
|
||||
__cpp_lib_execution 201603L [C++17]
|
||||
201902L [C++20]
|
||||
__cpp_lib_expected 202202L [C++2b]
|
||||
__cpp_lib_expected 202211L [C++2b]
|
||||
__cpp_lib_filesystem 201703L [C++17]
|
||||
__cpp_lib_format 202106L [C++20]
|
||||
__cpp_lib_format_ranges 202207L [C++2b]
|
||||
@ -4161,8 +4161,8 @@
|
||||
# ifndef __cpp_lib_expected
|
||||
# error "__cpp_lib_expected should be defined in c++2b"
|
||||
# endif
|
||||
# if __cpp_lib_expected != 202202L
|
||||
# error "__cpp_lib_expected should have the value 202202L in c++2b"
|
||||
# if __cpp_lib_expected != 202211L
|
||||
# error "__cpp_lib_expected should have the value 202211L in c++2b"
|
||||
# endif
|
||||
|
||||
# if !defined(_LIBCPP_AVAILABILITY_HAS_NO_FILESYSTEM)
|
||||
|
@ -0,0 +1,288 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) &;
|
||||
// template<class F> constexpr auto and_then(F&& f) const &;
|
||||
// template<class F> constexpr auto and_then(F&& f) &&;
|
||||
// template<class F> constexpr auto and_then(F&& f) const &&;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct LVal {
|
||||
constexpr std::expected<int, int> operator()(int&) { return 1; }
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CLVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
constexpr std::expected<int, int> operator()(const int&) { return 1; }
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct RVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
constexpr std::expected<int, int> operator()(int&&) { return 1; }
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CRVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
constexpr std::expected<int, int> operator()(const int&&) { return 1; }
|
||||
};
|
||||
|
||||
struct RefQual {
|
||||
constexpr std::expected<int, int> operator()(int) & { return 1; }
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct CRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
constexpr std::expected<int, int> operator()(int) const& { return 1; }
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
constexpr std::expected<int, int> operator()(int) && { return 1; }
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVCRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
constexpr std::expected<int, int> operator()(int) const&& { return 1; }
|
||||
};
|
||||
|
||||
struct UnexpectedLVal {
|
||||
constexpr std::expected<int, int> operator()(int&) { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct UnexpectedCLVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
constexpr std::expected<int, int> operator()(const int&) { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct UnexpectedRVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
constexpr std::expected<int, int> operator()(int&&) { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct UnexpectedCRVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
constexpr std::expected<int, int> operator()(const int&&) { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
};
|
||||
|
||||
struct UnexpectedRefQual {
|
||||
constexpr std::expected<int, int> operator()(int) & { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct UnexpectedCRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
constexpr std::expected<int, int> operator()(int) const& { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct UnexpectedRVRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
constexpr std::expected<int, int> operator()(int) && { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct UnexpectedRVCRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
constexpr std::expected<int, int> operator()(int) const&& { return std::expected<int, int>(std::unexpected<int>(5)); }
|
||||
};
|
||||
|
||||
struct NonCopyable {
|
||||
constexpr NonCopyable(int) {}
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
};
|
||||
|
||||
struct NonMovable {
|
||||
constexpr NonMovable(int) {}
|
||||
NonMovable(NonMovable&&) = delete;
|
||||
};
|
||||
|
||||
struct NonConst {
|
||||
std::expected<int, int> non_const() { return 1; }
|
||||
};
|
||||
|
||||
template <class E, class F>
|
||||
concept has_and_then = requires(E&& e, F&& f) {
|
||||
{std::forward<E>(e).and_then(std::forward<F>(f))};
|
||||
};
|
||||
|
||||
static_assert( has_and_then<std::expected<int, int>&, std::expected<int, int>(int&)>);
|
||||
static_assert(!has_and_then<std::expected<int, NonCopyable>&, std::expected<int, NonCopyable>(int&)>);
|
||||
static_assert( has_and_then<const std::expected<int, int>&, std::expected<int, int>(const int&)>);
|
||||
static_assert(!has_and_then<const std::expected<int, NonCopyable>&, std::expected<int, NonCopyable>(const int&)>);
|
||||
static_assert( has_and_then<std::expected<int, int>&&, std::expected<int, int>(int)>);
|
||||
static_assert(!has_and_then<std::expected<int, NonMovable>&&, std::expected<int, NonMovable>(int)>);
|
||||
static_assert( has_and_then<const std::expected<int, int>&&, std::expected<int, int>(const int)>);
|
||||
static_assert(!has_and_then<const std::expected<int, NonMovable>&&, std::expected<int, NonMovable>(const int)>);
|
||||
|
||||
// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
|
||||
static_assert(!has_and_then<const std::expected<int, std::unique_ptr<int>>&, int()>);
|
||||
static_assert(!has_and_then<const std::expected<int, std::unique_ptr<int>>&&, int()>);
|
||||
|
||||
// clang-format off
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
// Without &qualifier on F'soperator()
|
||||
{
|
||||
std::expected<int, int> e{0};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.and_then(LVal{});
|
||||
assert(val == 1);
|
||||
assert(e.and_then(UnexpectedLVal{}).error() == 5);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e{0};
|
||||
RefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.and_then(l);
|
||||
assert(val == 1);
|
||||
UnexpectedRefQual nl{};
|
||||
assert(e.and_then(nl).error() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e{0};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.and_then(CLVal{});
|
||||
assert(val == 1);
|
||||
assert(e.and_then(UnexpectedCLVal{}).error() == 5);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e{0};
|
||||
const CRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.and_then(l);
|
||||
assert(val == 1);
|
||||
const UnexpectedCRefQual nl{};
|
||||
assert(e.and_then(nl).error() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e{0};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).and_then(RVal{});
|
||||
assert(val == 1);
|
||||
assert(std::move(e).and_then(UnexpectedRVal{}).error() == 5);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e{0};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).and_then(RVRefQual{});
|
||||
assert(val == 1);
|
||||
assert(e.and_then(UnexpectedRVRefQual{}).error() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e{0};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).and_then(CRVal{});
|
||||
assert(val == 1);
|
||||
assert(std::move(e).and_then(UnexpectedCRVal{}).error() == 5);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e{0};
|
||||
const RVCRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).and_then(std::move(l));
|
||||
assert(val == 1);
|
||||
const UnexpectedRVCRefQual nl{};
|
||||
assert(std::move(e).and_then(std::move(nl)).error() == 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// check that the lambda body is not instantiated during overload resolution
|
||||
constexpr void test_sfinae() {
|
||||
std::expected<NonConst, int> e(std::unexpected<int>(2));
|
||||
auto l = [](auto&& x) { return x.non_const(); };
|
||||
e.and_then(l);
|
||||
std::move(e).and_then(l);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_sfinae();
|
||||
test_val_types();
|
||||
|
||||
std::expected<int, int> e(std::unexpected<int>(1));
|
||||
const auto& ce = e;
|
||||
|
||||
const auto never_called = [](int) {
|
||||
assert(false);
|
||||
return std::expected<int, int>();
|
||||
};
|
||||
|
||||
e.and_then(never_called);
|
||||
std::move(e).and_then(never_called);
|
||||
ce.and_then(never_called);
|
||||
std::move(ce).and_then(never_called);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) &;
|
||||
// template<class F> constexpr auto or_else(F&& f) const &;
|
||||
// template<class F> constexpr auto or_else(F&& f) &&;
|
||||
// template<class F> constexpr auto or_else(F&& f) const &&;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <expected>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct LVal {
|
||||
constexpr std::expected<int, int> operator()(int&) { return 1; }
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CLVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
constexpr std::expected<int, int> operator()(const int&) { return 1; }
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct RVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
constexpr std::expected<int, int> operator()(int&&) { return 1; }
|
||||
std::expected<int, int> operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CRVal {
|
||||
std::expected<int, int> operator()(int&) = delete;
|
||||
std::expected<int, int> operator()(const int&) = delete;
|
||||
std::expected<int, int> operator()(int&&) = delete;
|
||||
constexpr std::expected<int, int> operator()(const int&&) { return 1; }
|
||||
};
|
||||
|
||||
struct RefQual {
|
||||
constexpr std::expected<int, int> operator()(int) & { return 1; }
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct CRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
constexpr std::expected<int, int> operator()(int) const& { return 1; }
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
constexpr std::expected<int, int> operator()(int) && { return 1; }
|
||||
std::expected<int, int> operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVCRefQual {
|
||||
std::expected<int, int> operator()(int) & = delete;
|
||||
std::expected<int, int> operator()(int) const& = delete;
|
||||
std::expected<int, int> operator()(int) && = delete;
|
||||
constexpr std::expected<int, int> operator()(int) const&& { return 1; }
|
||||
};
|
||||
|
||||
template <class E, class F>
|
||||
concept has_or_else =
|
||||
requires(E&& e, F&& f) {
|
||||
{ std::forward<E>(e).or_else(std::forward<F>(f)) };
|
||||
};
|
||||
|
||||
// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
|
||||
static_assert(!has_or_else<const std::expected<std::unique_ptr<int>, int>&, int()>);
|
||||
static_assert(!has_or_else<const std::expected<std::unique_ptr<int>, int>&&, int()>);
|
||||
|
||||
// clang-format off
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(LVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
RefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// Without const& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(CLVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With const& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
const CRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.or_else(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// Without && qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(RVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With && qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(RVRefQual{});
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// Without const&& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(CRVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With const&& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
const RVCRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).or_else(std::move(l));
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
struct NonConst {
|
||||
std::expected<int, int> non_const() { return std::expected<int, int>(std::unexpect, 1); }
|
||||
};
|
||||
|
||||
// check that the lambda body is not instantiated during overload resolution
|
||||
constexpr void test_sfinae() {
|
||||
std::expected<int, NonConst> e{1};
|
||||
auto l = [](auto&& x) { return x.non_const(); };
|
||||
e.or_else(l);
|
||||
std::move(e).or_else(l);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_sfinae();
|
||||
test_val_types();
|
||||
|
||||
std::expected<int, int> e(1);
|
||||
const auto& ce = e;
|
||||
|
||||
const auto never_called = [](int) {
|
||||
assert(false);
|
||||
return std::expected<int, int>();
|
||||
};
|
||||
|
||||
e.or_else(never_called);
|
||||
std::move(e).or_else(never_called);
|
||||
ce.or_else(never_called);
|
||||
std::move(ce).or_else(never_called);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,251 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
|
||||
// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to
|
||||
// avoid this issue.
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto transform(F&& f) &;
|
||||
// template<class F> constexpr auto transform(F&& f) const &;
|
||||
// template<class F> constexpr auto transform(F&& f) &&;
|
||||
// template<class F> constexpr auto transform(F&& f) const &&;
|
||||
|
||||
#include <expected>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct LVal {
|
||||
constexpr int operator()(int&) { return 1; }
|
||||
int operator()(const int&) = delete;
|
||||
int operator()(int&&) = delete;
|
||||
int operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CLVal {
|
||||
int operator()(int&) = delete;
|
||||
constexpr int operator()(const int&) { return 1; }
|
||||
int operator()(int&&) = delete;
|
||||
int operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct RVal {
|
||||
int operator()(int&) = delete;
|
||||
int operator()(const int&) = delete;
|
||||
constexpr int operator()(int&&) { return 1; }
|
||||
int operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CRVal {
|
||||
int operator()(int&) = delete;
|
||||
int operator()(const int&) = delete;
|
||||
int operator()(int&&) = delete;
|
||||
constexpr int operator()(const int&&) { return 1; }
|
||||
};
|
||||
|
||||
struct RefQual {
|
||||
constexpr int operator()(int) & { return 1; }
|
||||
int operator()(int) const& = delete;
|
||||
int operator()(int) && = delete;
|
||||
int operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct CRefQual {
|
||||
int operator()(int) & = delete;
|
||||
constexpr int operator()(int) const& { return 1; }
|
||||
int operator()(int) && = delete;
|
||||
int operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVRefQual {
|
||||
int operator()(int) & = delete;
|
||||
int operator()(int) const& = delete;
|
||||
constexpr int operator()(int) && { return 1; }
|
||||
int operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVCRefQual {
|
||||
int operator()(int) & = delete;
|
||||
int operator()(int) const& = delete;
|
||||
int operator()(int) && = delete;
|
||||
constexpr int operator()(int) const&& { return 1; }
|
||||
};
|
||||
|
||||
struct NonCopy {
|
||||
int value;
|
||||
constexpr explicit NonCopy(int val) : value(val) {}
|
||||
NonCopy(const NonCopy&) = delete;
|
||||
};
|
||||
|
||||
struct NonConst {
|
||||
int non_const() { return 1; }
|
||||
};
|
||||
|
||||
template <class E, class F>
|
||||
concept has_transform =
|
||||
requires(E&& e, F&& f) {
|
||||
{ std::forward<E>(e).transform(std::forward<F>(f)) };
|
||||
};
|
||||
|
||||
// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
|
||||
static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&, int()>);
|
||||
static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&&, int()>);
|
||||
|
||||
// clang-format off
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
// Without &qualifier on F'soperator()
|
||||
{
|
||||
std::expected<int, int> e(0);
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(LVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(0);
|
||||
RefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(0);
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(CLVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(0);
|
||||
const CRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(0);
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(RVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(0);
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(RVRefQual{});
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(0);
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform(CRVal{});
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(0);
|
||||
const RVCRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform(std::move(l));
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
constexpr void test_take_val_return_void() {
|
||||
std::expected<int, int> e(1);
|
||||
int val = 0;
|
||||
e.transform([&val]<typename T>(T&&) -> void {
|
||||
static_assert(std::is_same_v<T, int&>);
|
||||
assert(val == 0);
|
||||
val = 1;
|
||||
});
|
||||
assert(val == 1);
|
||||
std::move(e).transform([&val]<typename T>(T&&) -> void {
|
||||
static_assert(std::is_same_v<T, int>);
|
||||
assert(val == 1);
|
||||
val = 2;
|
||||
});
|
||||
|
||||
const auto& ce = e;
|
||||
assert(val == 2);
|
||||
ce.transform([&val]<typename T>(T&&) -> void {
|
||||
static_assert(std::is_same_v<T, const int&>);
|
||||
assert(val == 2);
|
||||
val = 3;
|
||||
});
|
||||
assert(val == 3);
|
||||
std::move(ce).transform([&val]<typename T>(T&&) -> void {
|
||||
static_assert(std::is_same_v<T, const int>);
|
||||
assert(val == 3);
|
||||
val = 4;
|
||||
});
|
||||
assert(val == 4);
|
||||
}
|
||||
|
||||
// check val member is direct-non-list-initialized with invoke(std::forward<F>(f), value())
|
||||
constexpr void test_direct_non_list_init() {
|
||||
auto xform = [](int i) { return NonCopy(i); };
|
||||
std::expected<int, int> e(2);
|
||||
std::expected<NonCopy, int> n = e.transform(xform);
|
||||
assert(n.value().value == 2);
|
||||
}
|
||||
|
||||
// check that the lambda body is not instantiated during overload resolution
|
||||
constexpr void test_sfinae() {
|
||||
std::expected<NonConst, int> e(std::unexpected<int>(2));
|
||||
auto l = [](auto&& x) { return x.non_const(); };
|
||||
e.transform(l);
|
||||
std::move(e).transform(l);
|
||||
|
||||
std::expected<int, int> e1(std::unexpected<int>(1));
|
||||
const auto& ce1 = e1;
|
||||
const auto never_called = [](int) {
|
||||
assert(false);
|
||||
return std::expected<int, int>();
|
||||
};
|
||||
|
||||
e1.transform(never_called);
|
||||
std::move(e1).transform(never_called);
|
||||
ce1.and_then(never_called);
|
||||
std::move(ce1).transform(never_called);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_sfinae();
|
||||
test_val_types();
|
||||
test_direct_non_list_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,221 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
|
||||
// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to
|
||||
// avoid this issue.
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) &&;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &&;
|
||||
|
||||
#include <expected>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct LVal {
|
||||
constexpr int operator()(int&) { return 1; }
|
||||
int operator()(const int&) = delete;
|
||||
int operator()(int&&) = delete;
|
||||
int operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CLVal {
|
||||
int operator()(int&) = delete;
|
||||
constexpr int operator()(const int&) { return 1; }
|
||||
int operator()(int&&) = delete;
|
||||
int operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct RVal {
|
||||
int operator()(int&) = delete;
|
||||
int operator()(const int&) = delete;
|
||||
constexpr int operator()(int&&) { return 1; }
|
||||
int operator()(const int&&) = delete;
|
||||
};
|
||||
|
||||
struct CRVal {
|
||||
int operator()(int&) = delete;
|
||||
int operator()(const int&) = delete;
|
||||
int operator()(int&&) = delete;
|
||||
constexpr int operator()(const int&&) { return 1; }
|
||||
};
|
||||
|
||||
struct RefQual {
|
||||
constexpr int operator()(int) & { return 1; }
|
||||
int operator()(int) const& = delete;
|
||||
int operator()(int) && = delete;
|
||||
int operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct CRefQual {
|
||||
int operator()(int) & = delete;
|
||||
constexpr int operator()(int) const& { return 1; }
|
||||
int operator()(int) && = delete;
|
||||
int operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVRefQual {
|
||||
int operator()(int) & = delete;
|
||||
int operator()(int) const& = delete;
|
||||
constexpr int operator()(int) && { return 1; }
|
||||
int operator()(int) const&& = delete;
|
||||
};
|
||||
|
||||
struct RVCRefQual {
|
||||
int operator()(int) & = delete;
|
||||
int operator()(int) const& = delete;
|
||||
int operator()(int) && = delete;
|
||||
constexpr int operator()(int) const&& { return 1; }
|
||||
};
|
||||
|
||||
struct NonCopy {
|
||||
int value;
|
||||
constexpr explicit NonCopy(int val) : value(val) {}
|
||||
NonCopy(const NonCopy&) = delete;
|
||||
};
|
||||
|
||||
struct NonConst {
|
||||
int non_const() { return 1; }
|
||||
};
|
||||
|
||||
template <class E, class F>
|
||||
concept has_transform_error =
|
||||
requires(E&& e, F&& f) {
|
||||
{ std::forward<E>(e).transform_error(std::forward<F>(f)) };
|
||||
};
|
||||
|
||||
// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
|
||||
static_assert(!has_transform_error<const std::expected<std::unique_ptr<int>, int>&, int()>);
|
||||
static_assert(!has_transform_error<const std::expected<std::unique_ptr<int>, int>&&, int()>);
|
||||
|
||||
// clang-format off
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
// Without & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform_error(LVal{});
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// With & qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
RefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform_error(l);
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
// Without const& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform_error(CLVal{});
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// With const& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
const CRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = e.transform_error(l);
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
// Without && qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform_error(RVal{});
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// With && qualifier on F's operator()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform_error(RVRefQual{});
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
// Without const&& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform_error(CRVal{});
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// With const&& qualifier on F's operator()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpected<int>(0));
|
||||
const RVCRefQual l{};
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(e).transform_error(std::move(l));
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// check unex member is direct-non-list-initialized with invoke(std::forward<F>(f), error())
|
||||
constexpr void test_direct_non_list_init() {
|
||||
auto xform = [](int i) { return NonCopy(i); };
|
||||
std::expected<int, int> e(std::unexpected<int>(2));
|
||||
std::expected<int, NonCopy> n = e.transform_error(xform);
|
||||
assert(n.error().value == 2);
|
||||
}
|
||||
|
||||
// check that the lambda body is not instantiated during overload resolution
|
||||
constexpr void test_sfinae() {
|
||||
std::expected<int, NonConst> e(2);
|
||||
auto l = [](auto&& x) { return x.non_const(); };
|
||||
e.transform_error(l);
|
||||
std::move(e).transform_error(l);
|
||||
|
||||
std::expected<int, int> e1;
|
||||
const auto& ce1 = e1;
|
||||
|
||||
const auto never_called = [](int) {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
|
||||
e1.transform_error(never_called);
|
||||
std::move(e1).transform_error(never_called);
|
||||
ce1.transform_error(never_called);
|
||||
std::move(ce1).transform_error(never_called);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_sfinae();
|
||||
test_val_types();
|
||||
test_direct_non_list_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// template<class G = E> constexpr E error_or(G&& e) const &;
|
||||
// template<class G = E> constexpr E error_or(G&& e) &&;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <expected>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct ConstructFromInt {
|
||||
int value;
|
||||
constexpr ConstructFromInt(int v) : value(v) {}
|
||||
};
|
||||
|
||||
constexpr bool test_default_template_arg() {
|
||||
// const &, has_value()
|
||||
{
|
||||
const std::expected<int, ConstructFromInt> e(5);
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = e.error_or(10);
|
||||
assert(x.value == 10);
|
||||
}
|
||||
|
||||
// const &, !has_value()
|
||||
{
|
||||
const std::expected<int, ConstructFromInt> e(std::unexpect, 5);
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = e.error_or(10);
|
||||
assert(x.value == 5);
|
||||
}
|
||||
|
||||
// &&, has_value()
|
||||
{
|
||||
const std::expected<int, ConstructFromInt> e(5);
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x.value == 10);
|
||||
}
|
||||
|
||||
// &&, !has_value()
|
||||
{
|
||||
const std::expected<int, ConstructFromInt> e(std::unexpect, 5);
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x.value == 5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// const &, has_value()
|
||||
{
|
||||
const std::expected<int, int> e(5);
|
||||
std::same_as<int> decltype(auto) x = e.error_or(10);
|
||||
assert(x == 10);
|
||||
}
|
||||
|
||||
// const &, !has_value()
|
||||
{
|
||||
const std::expected<int, int> e(std::unexpect, 5);
|
||||
std::same_as<int> decltype(auto) x = e.error_or(10);
|
||||
assert(x == 5);
|
||||
}
|
||||
|
||||
// &&, has_value()
|
||||
{
|
||||
std::expected<int, int> e(5);
|
||||
std::same_as<int> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x == 10);
|
||||
}
|
||||
|
||||
// &&, !has_value()
|
||||
{
|
||||
std::expected<int, int> e(std::unexpect, 5);
|
||||
std::same_as<int> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x == 5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
test_default_template_arg();
|
||||
static_assert(test_default_template_arg());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto and_then(F&& f) &;
|
||||
// template<class F> constexpr auto and_then(F&& f) const &;
|
||||
// template<class F> constexpr auto and_then(F&& f) &&;
|
||||
// template<class F> constexpr auto and_then(F&& f) const &&;
|
||||
|
||||
#include <expected>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct NonCopyable {
|
||||
constexpr NonCopyable(int) {}
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
};
|
||||
|
||||
struct NonMovable {
|
||||
constexpr NonMovable(int) {}
|
||||
NonMovable(NonMovable&&) = delete;
|
||||
};
|
||||
|
||||
template <class E, class F>
|
||||
concept has_and_then =
|
||||
requires(E&& e, F&& f) {
|
||||
{ std::forward<E>(e).and_then(std::forward<F>(f)) };
|
||||
};
|
||||
|
||||
std::expected<void, int> return_int() { return {}; }
|
||||
std::expected<void, NonCopyable> return_noncopyable() { return {}; }
|
||||
std::expected<void, NonMovable> return_nonmovable() { return {}; }
|
||||
|
||||
static_assert(has_and_then<std::expected<void, int>&, decltype(return_int)>);
|
||||
static_assert(!has_and_then<std::expected<void, NonCopyable>&, decltype(return_noncopyable)>);
|
||||
static_assert(has_and_then<const std::expected<void, int>&, decltype(return_int)>);
|
||||
static_assert(!has_and_then<const std::expected<void, NonCopyable>&, decltype(return_noncopyable)>);
|
||||
static_assert(has_and_then<std::expected<void, int>&&, decltype(return_int)>);
|
||||
static_assert(!has_and_then<std::expected<void, NonMovable>&&, decltype(return_nonmovable)>);
|
||||
static_assert(has_and_then<const std::expected<void, int>&&, decltype(return_int)>);
|
||||
static_assert(!has_and_then<const std::expected<void, NonMovable>&&, decltype(return_nonmovable)>);
|
||||
|
||||
// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
|
||||
static_assert(!has_and_then<const std::expected<int, std::unique_ptr<int>>&, int()>);
|
||||
static_assert(!has_and_then<const std::expected<int, std::unique_ptr<int>>&&, int()>);
|
||||
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
auto l = [] -> std::expected<int, int> { return 2; };
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.and_then(l);
|
||||
assert(val == 2);
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto l = [] -> std::expected<int, int> { return 2; };
|
||||
const std::expected<void, int> v;
|
||||
assert(v.and_then(l).value() == 2);
|
||||
static_assert(std::is_same_v< decltype(v.and_then(l)), std::expected<int, int>>);
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto l = [] -> std::expected<int, int> { return 2; };
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(l);
|
||||
assert(val == 2);
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto l = [] -> std::expected<int, int> { return 2; };
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(l);
|
||||
assert(val == 2);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_fail() {
|
||||
// Test & overload
|
||||
{
|
||||
auto f = [] -> std::expected<int, int> {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.and_then(f);
|
||||
assert(val.error() == 2);
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto f = [] -> std::expected<int, int> {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
const std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.and_then(f);
|
||||
assert(val.error() == 2);
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto f = [] -> std::expected<int, int> {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(f);
|
||||
assert(val.error() == 2);
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto f = [] -> std::expected<int, int> {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
const std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).and_then(f);
|
||||
assert(val.error() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_fail();
|
||||
test_val_types();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto or_else(F&& f) &;
|
||||
// template<class F> constexpr auto or_else(F&& f) const &;
|
||||
// template<class F> constexpr auto or_else(F&& f) &&;
|
||||
// template<class F> constexpr auto or_else(F&& f) const &&;
|
||||
|
||||
#include <expected>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
auto l = [](auto) -> std::expected<void, long> { return {}; };
|
||||
std::expected<void, int> v(std::unexpected<int>(1));
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = v.or_else(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto l = [](auto) -> std::expected<void, long> { return {}; };
|
||||
const std::expected<void, int> v(std::unexpected<int>(1));
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = v.or_else(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto l = [](auto) -> std::expected<void, long> { return {}; };
|
||||
std::expected<void, int> v(std::unexpected<int>(1));
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = std::move(v).or_else(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto l = [](auto) -> std::expected<void, long> { return {}; };
|
||||
const std::expected<void, int> v(std::unexpected<int>(1));
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = std::move(v).or_else(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_fail() {
|
||||
auto never_called = [](auto) -> std::expected<void, long> {
|
||||
assert(false);
|
||||
return std::expected<void, long>(std::unexpected<long>(5));
|
||||
};
|
||||
|
||||
// Test & overload
|
||||
{
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = v.or_else(never_called);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = v.or_else(never_called);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = std::move(v).or_else(never_called);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, long>> decltype(auto) val = std::move(v).or_else(never_called);
|
||||
assert(val.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_fail();
|
||||
test_val_types();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) &&;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &&;
|
||||
|
||||
#include <expected>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
template <class E, class F>
|
||||
concept has_transform =
|
||||
requires(E&& e, F&& f) {
|
||||
{ std::forward<E>(e).transform(std::forward<F>(f)) };
|
||||
};
|
||||
|
||||
// [LWG 3877] https://cplusplus.github.io/LWG/issue3877, check constraint failing but not compile error inside the function body.
|
||||
static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&, int()>);
|
||||
static_assert(!has_transform<const std::expected<int, std::unique_ptr<int>>&&, int()>);
|
||||
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
auto l = [] -> int { return 1; };
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.transform(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto l = [] -> int { return 1; };
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.transform(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto l = [] -> int { return 1; };
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).transform(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto l = [] -> int { return 1; };
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).transform(l);
|
||||
assert(val == 1);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_fail() {
|
||||
// Test & overload
|
||||
{
|
||||
auto l = [] -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
std::expected<void, int> v(std::unexpected<int>(5));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.transform(l);
|
||||
assert(val.error() == 5);
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto l = [] -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
const std::expected<void, int> v(std::unexpected<int>(5));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = v.transform(l);
|
||||
assert(val.error() == 5);
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto l = [] -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
std::expected<void, int> v(std::unexpected<int>(5));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).transform(l);
|
||||
assert(val.error() == 5);
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto l = [] -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
const std::expected<void, int> v(std::unexpected<int>(5));
|
||||
std::same_as<std::expected<int, int>> decltype(auto) val = std::move(v).transform(l);
|
||||
assert(val.error() == 5);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_fail();
|
||||
test_val_types();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// GCC has a issue for `Guaranteed copy elision for potentially-overlapping non-static data members`,
|
||||
// please refer to: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108333, but we have a workaround to
|
||||
// avoid this issue.
|
||||
|
||||
// <expected>
|
||||
|
||||
// template<class F> constexpr auto transform_error(F&& f) &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &;
|
||||
// template<class F> constexpr auto transform_error(F&& f) &&;
|
||||
// template<class F> constexpr auto transform_error(F&& f) const &&;
|
||||
|
||||
#include <expected>
|
||||
#include <concepts>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct NonCopy {
|
||||
int value;
|
||||
constexpr explicit NonCopy(int val) : value(val) {}
|
||||
NonCopy(const NonCopy&) = delete;
|
||||
};
|
||||
|
||||
constexpr void test_val_types() {
|
||||
// Test & overload
|
||||
{
|
||||
auto l = [](auto) -> int { return 1; };
|
||||
std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto l = [](auto) -> int { return 1; };
|
||||
const std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto l = [](auto) -> int { return 1; };
|
||||
std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto l = [](auto) -> int { return 1; };
|
||||
const std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
|
||||
assert(val.error() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr void test_fail() {
|
||||
// Test & overload
|
||||
{
|
||||
auto l = [](auto) -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test const& overload
|
||||
{
|
||||
auto l = [](auto) -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = v.transform_error(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test && overload
|
||||
{
|
||||
auto l = [](auto) -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
|
||||
// Test const&& overload
|
||||
{
|
||||
auto l = [](auto) -> int {
|
||||
assert(false);
|
||||
return 0;
|
||||
};
|
||||
const std::expected<void, int> v;
|
||||
std::same_as<std::expected<void, int>> decltype(auto) val = std::move(v).transform_error(l);
|
||||
assert(val.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
// check unex member is direct-non-list-initialized with invoke(std::forward<F>(f))
|
||||
constexpr void test_direct_non_list_init() {
|
||||
auto x = [](int i) { return NonCopy(i); };
|
||||
std::expected<void, int> v(std::unexpected<int>(2));
|
||||
std::expected<void, NonCopy> nv = v.transform_error(x);
|
||||
assert(nv.error().value == 2);
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
test_fail();
|
||||
test_val_types();
|
||||
test_direct_non_list_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
|
||||
|
||||
// template<class G = E> constexpr E error_or(G&& e) const &;
|
||||
// template<class G = E> constexpr E error_or(G&& e) &&;
|
||||
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <expected>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
struct ConstructFromInt {
|
||||
int value;
|
||||
constexpr ConstructFromInt(int v) : value(v) {}
|
||||
};
|
||||
|
||||
constexpr bool test_default_template_arg() {
|
||||
// const &, has_value()
|
||||
{
|
||||
const std::expected<void, ConstructFromInt> e;
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = e.error_or(10);
|
||||
assert(x.value == 10);
|
||||
}
|
||||
|
||||
// const &, !has_value()
|
||||
{
|
||||
const std::expected<void, ConstructFromInt> e(std::unexpect, 5);
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = e.error_or(10);
|
||||
assert(x.value == 5);
|
||||
}
|
||||
|
||||
// &&, has_value()
|
||||
{
|
||||
const std::expected<void, ConstructFromInt> e;
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x.value == 10);
|
||||
}
|
||||
|
||||
// &&, !has_value()
|
||||
{
|
||||
const std::expected<void, ConstructFromInt> e(std::unexpect, 5);
|
||||
std::same_as<ConstructFromInt> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x.value == 5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test() {
|
||||
// const &, has_value()
|
||||
{
|
||||
const std::expected<void, int> e;
|
||||
std::same_as<int> decltype(auto) x = e.error_or(10);
|
||||
assert(x == 10);
|
||||
}
|
||||
|
||||
// const &, !has_value()
|
||||
{
|
||||
const std::expected<void, int> e(std::unexpect, 5);
|
||||
std::same_as<int> decltype(auto) x = e.error_or(10);
|
||||
assert(x == 5);
|
||||
}
|
||||
|
||||
// &&, has_value()
|
||||
{
|
||||
std::expected<void, int> e;
|
||||
std::same_as<int> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x == 10);
|
||||
}
|
||||
|
||||
// &&, !has_value()
|
||||
{
|
||||
std::expected<void, int> e(std::unexpect, 5);
|
||||
std::same_as<int> decltype(auto) x = std::move(e).error_or(10);
|
||||
assert(x == 5);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
test();
|
||||
static_assert(test());
|
||||
test_default_template_arg();
|
||||
static_assert(test_default_template_arg());
|
||||
|
||||
return 0;
|
||||
}
|
@ -306,7 +306,7 @@ feature_test_macros = [ add_version_header(x) for x in [
|
||||
"unimplemented": True,
|
||||
}, {
|
||||
"name": "__cpp_lib_expected",
|
||||
"values": { "c++2b": 202202 },
|
||||
"values": { "c++2b": 202211 },
|
||||
"headers": ["expected"],
|
||||
}, {
|
||||
"name": "__cpp_lib_filesystem",
|
||||
|
Loading…
x
Reference in New Issue
Block a user