@@ -745,8 +745,7 @@ namespace __expected
{
if (_M_has_value) [[likely]]
return std::move(_M_val);
- _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(
- std::move(_M_unex)));
+ _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
}
constexpr _Tp&&
@@ -754,8 +753,7 @@ namespace __expected
{
if (_M_has_value) [[likely]]
return std::move(_M_val);
- _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(
- std::move(_M_unex)));
+ _GLIBCXX_THROW_OR_ABORT(bad_expected_access<_Er>(std::move(_M_unex)));
}
constexpr const _Er&
@@ -849,9 +847,9 @@ namespace __expected
static_assert(is_same_v<typename _Up::error_type, _Er>);
if (has_value())
- return std::__invoke(std::forward<_Fn>(__f), value());
+ return std::__invoke(std::forward<_Fn>(__f), _M_val);
else
- return _Up(unexpect, error());
+ return _Up(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
@@ -863,9 +861,9 @@ namespace __expected
static_assert(is_same_v<typename _Up::error_type, _Er>);
if (has_value())
- return std::__invoke(std::forward<_Fn>(__f), value());
+ return std::__invoke(std::forward<_Fn>(__f), _M_val);
else
- return _Up(unexpect, error());
+ return _Up(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, _Er>
@@ -877,9 +875,9 @@ namespace __expected
static_assert(is_same_v<typename _Up::error_type, _Er>);
if (has_value())
- return std::__invoke(std::forward<_Fn>(__f), std::move(value()));
+ return std::__invoke(std::forward<_Fn>(__f), std::move(_M_val));
else
- return _Up(unexpect, std::move(error()));
+ return _Up(unexpect, std::move(_M_unex));
}
@@ -892,9 +890,9 @@ namespace __expected
static_assert(is_same_v<typename _Up::error_type, _Er>);
if (has_value())
- return std::__invoke(std::forward<_Fn>(__f), std::move(value()));
+ return std::__invoke(std::forward<_Fn>(__f), std::move(_M_val));
else
- return _Up(unexpect, std::move(error()));
+ return _Up(unexpect, std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Tp, _Tp&>
@@ -906,9 +904,9 @@ namespace __expected
static_assert(is_same_v<typename _Gr::value_type, _Tp>);
if (has_value())
- return _Gr(in_place, value());
+ return _Gr(in_place, _M_val);
else
- return std::__invoke(std::forward<_Fn>(__f), error());
+ return std::__invoke(std::forward<_Fn>(__f), _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Tp, const _Tp&>
@@ -920,9 +918,9 @@ namespace __expected
static_assert(is_same_v<typename _Gr::value_type, _Tp>);
if (has_value())
- return _Gr(in_place, value());
+ return _Gr(in_place, _M_val);
else
- return std::__invoke(std::forward<_Fn>(__f), error());
+ return std::__invoke(std::forward<_Fn>(__f), _M_unex);
}
@@ -935,9 +933,9 @@ namespace __expected
static_assert(is_same_v<typename _Gr::value_type, _Tp>);
if (has_value())
- return _Gr(in_place, std::move(value()));
+ return _Gr(in_place, std::move(_M_val));
else
- return std::__invoke(std::forward<_Fn>(__f), std::move(error()));
+ return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Tp, const _Tp>
@@ -949,9 +947,9 @@ namespace __expected
static_assert(is_same_v<typename _Gr::value_type, _Tp>);
if (has_value())
- return _Gr(in_place, std::move(value()));
+ return _Gr(in_place, std::move(_M_val));
else
- return std::__invoke(std::forward<_Fn>(__f), std::move(error()));
+ return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Er, _Er&>
@@ -967,7 +965,7 @@ namespace __expected
_M_val);
});
else
- return _Res(unexpect, std::move(error()));
+ return _Res(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
@@ -983,7 +981,7 @@ namespace __expected
_M_val);
});
else
- return _Res(unexpect, std::move(error()));
+ return _Res(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, _Er>
@@ -999,7 +997,7 @@ namespace __expected
std::move(_M_val));
});
else
- return _Res(unexpect, std::move(error()));
+ return _Res(unexpect, std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er>
@@ -1015,7 +1013,7 @@ namespace __expected
std::move(_M_val));
});
else
- return _Res(unexpect, std::move(error()));
+ return _Res(unexpect, std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Tp, _Tp&>
@@ -1026,7 +1024,7 @@ namespace __expected
using _Res = expected<_Tp, _Gr>;
if (has_value())
- return _Res(in_place, value());
+ return _Res(in_place, _M_val);
else
return _Res(__unexpect_inv{}, [&]() {
return std::__invoke(std::forward<_Fn>(__f),
@@ -1042,7 +1040,7 @@ namespace __expected
using _Res = expected<_Tp, _Gr>;
if (has_value())
- return _Res(in_place, value());
+ return _Res(in_place, _M_val);
else
return _Res(__unexpect_inv{}, [&]() {
return std::__invoke(std::forward<_Fn>(__f),
@@ -1058,7 +1056,7 @@ namespace __expected
using _Res = expected<_Tp, _Gr>;
if (has_value())
- return _Res(in_place, std::move(value()));
+ return _Res(in_place, std::move(_M_val));
else
return _Res(__unexpect_inv{}, [&]() {
return std::__invoke(std::forward<_Fn>(__f),
@@ -1074,7 +1072,7 @@ namespace __expected
using _Res = expected<_Tp, _Gr>;
if (has_value())
- return _Res(in_place, std::move(value()));
+ return _Res(in_place, std::move(_M_val));
else
return _Res(__unexpect_inv{}, [&]() {
return std::__invoke(std::forward<_Fn>(__f),
@@ -1530,7 +1528,7 @@ namespace __expected
if (has_value())
return std::__invoke(std::forward<_Fn>(__f));
else
- return _Up(unexpect, error());
+ return _Up(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
@@ -1544,7 +1542,7 @@ namespace __expected
if (has_value())
return std::__invoke(std::forward<_Fn>(__f));
else
- return _Up(unexpect, error());
+ return _Up(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, _Er>
@@ -1558,7 +1556,7 @@ namespace __expected
if (has_value())
return std::__invoke(std::forward<_Fn>(__f));
else
- return _Up(unexpect, std::move(error()));
+ return _Up(unexpect, std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er>
@@ -1572,7 +1570,7 @@ namespace __expected
if (has_value())
return std::__invoke(std::forward<_Fn>(__f));
else
- return _Up(unexpect, std::move(error()));
+ return _Up(unexpect, std::move(_M_unex));
}
template<typename _Fn>
@@ -1586,7 +1584,7 @@ namespace __expected
if (has_value())
return _Gr();
else
- return std::__invoke(std::forward<_Fn>(__f), error());
+ return std::__invoke(std::forward<_Fn>(__f), _M_unex);
}
template<typename _Fn>
@@ -1600,7 +1598,7 @@ namespace __expected
if (has_value())
return _Gr();
else
- return std::__invoke(std::forward<_Fn>(__f), error());
+ return std::__invoke(std::forward<_Fn>(__f), _M_unex);
}
template<typename _Fn>
@@ -1614,7 +1612,7 @@ namespace __expected
if (has_value())
return _Gr();
else
- return std::__invoke(std::forward<_Fn>(__f), std::move(error()));
+ return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
}
template<typename _Fn>
@@ -1628,7 +1626,7 @@ namespace __expected
if (has_value())
return _Gr();
else
- return std::__invoke(std::forward<_Fn>(__f), std::move(error()));
+ return std::__invoke(std::forward<_Fn>(__f), std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Er, _Er&>
@@ -1641,7 +1639,7 @@ namespace __expected
if (has_value())
return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
else
- return _Res(unexpect, error());
+ return _Res(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er&>
@@ -1654,7 +1652,7 @@ namespace __expected
if (has_value())
return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
else
- return _Res(unexpect, error());
+ return _Res(unexpect, _M_unex);
}
template<typename _Fn> requires is_constructible_v<_Er, _Er>
@@ -1667,7 +1665,7 @@ namespace __expected
if (has_value())
return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
else
- return _Res(unexpect, std::move(error()));
+ return _Res(unexpect, std::move(_M_unex));
}
template<typename _Fn> requires is_constructible_v<_Er, const _Er>
@@ -1680,7 +1678,7 @@ namespace __expected
if (has_value())
return _Res(__in_place_inv{}, std::forward<_Fn>(__f));
else
- return _Res(unexpect, std::move(error()));
+ return _Res(unexpect, std::move(_M_unex));
}
template<typename _Fn>
@@ -1,6 +1,8 @@
// { dg-options "-std=gnu++23" }
// { dg-do compile { target c++23 } }
+// LWG 3877. Incorrect constraints on const-qualified monadic overloads
+
#include <expected>
struct T1
@@ -20,45 +22,134 @@ struct T3
T3(const T3&&) { }
};
+template<typename Exp, typename F>
+concept Has_and_then = requires(Exp&& exp, F f) {
+ std::forward<Exp>(exp).and_then(f);
+};
+
+using ExpiT1 = std::expected<int, T1>;
+static_assert( Has_and_then<ExpiT1&, ExpiT1(int)> );
+static_assert( Has_and_then<const ExpiT1&, ExpiT1(int)> );
+static_assert( Has_and_then<ExpiT1&&, ExpiT1(int)> );
+static_assert( Has_and_then<const ExpiT1&&, ExpiT1(int)> );
+
+using ExpiT2 = std::expected<int, T2>;
+static_assert( !Has_and_then<ExpiT2&, ExpiT2(int)> );
+static_assert( !Has_and_then<const ExpiT2&, ExpiT2(int)> );
+static_assert( !Has_and_then<ExpiT2&&, ExpiT2(int)> );
+static_assert( !Has_and_then<const ExpiT2&&, ExpiT2(int)> );
+
+using ExpiT3 = std::expected<int, T3>;
+static_assert( Has_and_then<ExpiT3&, ExpiT3(int)> );
+static_assert( !Has_and_then<const ExpiT3&, ExpiT3(int)> );
+static_assert( Has_and_then<ExpiT3&&, ExpiT3(int)> ); // uses and_then(F) const &&
+static_assert( Has_and_then<const ExpiT3&&, ExpiT3(int)> );
+
template<typename Exp, typename F>
concept Has_or_else = requires(Exp&& exp, F f) {
std::forward<Exp>(exp).or_else(f);
};
-using E1 = std::expected<T1, int>;
-static_assert( Has_or_else<E1&, E1(int)> );
-static_assert( Has_or_else<const E1&, E1(int)> );
-static_assert( Has_or_else<E1&&, E1(int)> );
-static_assert( Has_or_else<const E1&&, E1(int)> );
+using ExpT1i = std::expected<T1, int>;
+static_assert( Has_or_else<ExpT1i&, ExpT1i(int)> );
+static_assert( Has_or_else<const ExpT1i&, ExpT1i(int)> );
+static_assert( Has_or_else<ExpT1i&&, ExpT1i(int)> );
+static_assert( Has_or_else<const ExpT1i&&, ExpT1i(int)> );
-using E2 = std::expected<T2, int>;
-static_assert( !Has_or_else<E2&, E2(int)> );
-static_assert( !Has_or_else<const E2&, E2(int)> );
-static_assert( !Has_or_else<E2&&, E2(int)> );
-static_assert( !Has_or_else<const E2&&, E2(int)> );
+using ExpT2i = std::expected<T2, int>;
+static_assert( !Has_or_else<ExpT2i&, ExpT2i(int)> );
+static_assert( !Has_or_else<const ExpT2i&, ExpT2i(int)> );
+static_assert( !Has_or_else<ExpT2i&&, ExpT2i(int)> );
+static_assert( !Has_or_else<const ExpT2i&&, ExpT2i(int)> );
-using E3 = std::expected<T3, int>;
-static_assert( Has_or_else<E3&, E3(int)> );
-static_assert( !Has_or_else<const E3&, E3(int)> );
-static_assert( Has_or_else<E3&&, E3(int)> ); // uses or_else(F) const &&
-static_assert( Has_or_else<const E3&&, E3(int)> );
+using ExpT3i = std::expected<T3, int>;
+static_assert( Has_or_else<ExpT3i&, ExpT3i(int)> );
+static_assert( !Has_or_else<const ExpT3i&, ExpT3i(int)> );
+static_assert( Has_or_else<ExpT3i&&, ExpT3i(int)> ); // uses or_else(F) const &&
+static_assert( Has_or_else<const ExpT3i&&, ExpT3i(int)> );
+
+template<typename Exp, typename F>
+concept Has_transform = requires(Exp&& exp, F f) {
+ std::forward<Exp>(exp).transform(f);
+};
+
+static_assert( Has_transform<ExpiT1&, int(int)> );
+static_assert( Has_transform<const ExpiT1&, int(int)> );
+static_assert( Has_transform<ExpiT1&&, int(int)> );
+static_assert( Has_transform<const ExpiT1&&, int(int)> );
+
+static_assert( !Has_transform<ExpiT2&, int(int)> );
+static_assert( !Has_transform<const ExpiT2&, int(int)> );
+static_assert( !Has_transform<ExpiT2&&, int(int)> );
+static_assert( !Has_transform<const ExpiT2&&, int(int)> );
+
+static_assert( Has_transform<ExpiT3&, int(int)> );
+static_assert( !Has_transform<const ExpiT3&, int(int)> );
+static_assert( Has_transform<ExpiT3&&, int(int)> ); // uses transform(F) const &&
+static_assert( Has_transform<const ExpiT3&&, int(int)> );
template<typename Exp, typename F>
concept Has_transform_error = requires(Exp&& exp, F f) {
std::forward<Exp>(exp).transform_error(f);
};
-static_assert( Has_transform_error<E1&, int(int)> );
-static_assert( Has_transform_error<const E1&, int(int)> );
-static_assert( Has_transform_error<E1&&, int(int)> );
-static_assert( Has_transform_error<const E1&&, int(int)> );
+static_assert( Has_transform_error<ExpT1i&, int(int)> );
+static_assert( Has_transform_error<const ExpT1i&, int(int)> );
+static_assert( Has_transform_error<ExpT1i&&, int(int)> );
+static_assert( Has_transform_error<const ExpT1i&&, int(int)> );
-static_assert( !Has_transform_error<E2&, int(int)> );
-static_assert( !Has_transform_error<const E2&, int(int)> );
-static_assert( !Has_transform_error<E2&&, int(int)> );
-static_assert( !Has_transform_error<const E2&&, int(int)> );
+static_assert( !Has_transform_error<ExpT2i&, int(int)> );
+static_assert( !Has_transform_error<const ExpT2i&, int(int)> );
+static_assert( !Has_transform_error<ExpT2i&&, int(int)> );
+static_assert( !Has_transform_error<const ExpT2i&&, int(int)> );
-static_assert( Has_transform_error<E3&, int(int)> );
-static_assert( !Has_transform_error<const E3&, int(int)> );
-static_assert( Has_transform_error<E3&&, int(int)> ); // uses transform_error(F) const &&
-static_assert( Has_transform_error<const E3&&, int(int)> );
+static_assert( Has_transform_error<ExpT3i&, int(int)> );
+static_assert( !Has_transform_error<const ExpT3i&, int(int)> );
+static_assert( Has_transform_error<ExpT3i&&, int(int)> ); // uses transform_error(F) const &&
+static_assert( Has_transform_error<const ExpT3i&&, int(int)> );
+
+// std::expected<cv void, E>
+
+using ExpvT1 = std::expected<void, T1>;
+static_assert( Has_and_then<ExpvT1&, ExpvT1()> );
+static_assert( Has_and_then<const ExpvT1&, ExpvT1()> );
+static_assert( Has_and_then<ExpvT1&&, ExpvT1()> );
+static_assert( Has_and_then<const ExpvT1&&, ExpvT1()> );
+
+using ExpvT2 = std::expected<void, T2>;
+static_assert( !Has_and_then<ExpvT2&, ExpvT2()> );
+static_assert( !Has_and_then<const ExpvT2&, ExpvT2()> );
+static_assert( !Has_and_then<ExpvT2&&, ExpvT2()> );
+static_assert( !Has_and_then<const ExpvT2&&, ExpvT2()> );
+
+using ExpvT3 = std::expected<void, T3>;
+static_assert( Has_and_then<ExpvT3&, ExpvT3()> );
+static_assert( !Has_and_then<const ExpvT3&, ExpvT3()> );
+static_assert( Has_and_then<ExpvT3&&, ExpvT3()> ); // uses and_then(F) const &&
+static_assert( Has_and_then<const ExpvT3&&, ExpvT3()> );
+
+using Expvi = std::expected<void, int>;
+static_assert( Has_or_else<Expvi&, Expvi(int)> );
+static_assert( Has_or_else<const Expvi&, Expvi(int)> );
+static_assert( Has_or_else<Expvi&&, Expvi(int)> );
+static_assert( Has_or_else<const Expvi&&, Expvi(int)> );
+
+static_assert( Has_transform<ExpvT1&, int()> );
+static_assert( Has_transform<const ExpvT1&, int()> );
+static_assert( Has_transform<ExpvT1&&, int()> );
+static_assert( Has_transform<const ExpvT1&&, int()> );
+
+static_assert( !Has_transform<ExpvT2&, int()> );
+static_assert( !Has_transform<const ExpvT2&, int()> );
+static_assert( !Has_transform<ExpvT2&&, int()> );
+static_assert( !Has_transform<const ExpvT2&&, int()> );
+
+static_assert( Has_transform<ExpvT3&, int()> );
+static_assert( !Has_transform<const ExpvT3&, int()> );
+static_assert( Has_transform<ExpvT3&&, int()> ); // uses transform(F) const &&
+static_assert( Has_transform<const ExpvT3&&, int()> );
+
+static_assert( Has_transform_error<Expvi&, int(int)> );
+static_assert( Has_transform_error<const Expvi&, int(int)> );
+static_assert( Has_transform_error<Expvi&&, int(int)> );
+static_assert( Has_transform_error<const Expvi&&, int(int)> );
new file mode 100644
@@ -0,0 +1,142 @@
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+// LWG 3938. Cannot use std::expected monadic ops with move-only error_type
+
+#include <expected>
+#include <testsuite_hooks.h>
+
+struct MoveOnly {
+ constexpr MoveOnly(int i) : i(i) { }
+ constexpr MoveOnly(MoveOnly&&) = default;
+ constexpr MoveOnly(const MoveOnly&& mo) : i(mo.i) { }
+ constexpr bool operator==(const MoveOnly&) const = default;
+ int i;
+};
+
+constexpr bool
+test_and_then()
+{
+ auto fun = [](int i) { return std::expected<long, MoveOnly>(i); };
+
+ std::expected<int, MoveOnly> good(9);
+ std::expected<long, MoveOnly> e1 = std::move(good).and_then(fun);
+ VERIFY( e1 == good );
+ const auto& gooder = good;
+ std::expected<long, MoveOnly> e2 = std::move(gooder).and_then(fun);
+ VERIFY( e2 == gooder );
+
+ std::expected<int, MoveOnly> bad(std::unexpect, 99);
+ std::expected<long, MoveOnly> e3 = std::move(bad).and_then(fun);
+ VERIFY( e3 == bad );
+ const auto& badder = bad;
+ std::expected<long, MoveOnly> e4 = std::move(badder).and_then(fun);
+ VERIFY( e4 == badder );
+
+ auto vun = [] { return std::expected<long, MoveOnly>(1); };
+ std::expected<void, MoveOnly> vud;
+ std::expected<long, MoveOnly> e5 = std::move(vud).and_then(vun);
+ VERIFY( *e5 == 1 );
+ const auto& vudder = vud;
+ std::expected<long, MoveOnly> e6 = std::move(vudder).and_then(vun);
+ VERIFY( *e6 == 1 );
+
+ return true;
+}
+
+static_assert( test_and_then() );
+
+constexpr bool
+test_or_else()
+{
+ auto fun = [](const MoveOnly&& mo) { return std::expected<int, long>(mo.i); };
+
+ std::expected<int, MoveOnly> good(9);
+ std::expected<int, long> e1 = std::move(good).or_else(fun);
+ VERIFY( e1 == good );
+ const auto& gooder = good;
+ std::expected<int, long> e2 = std::move(gooder).or_else(fun);
+ VERIFY( e2 == gooder );
+
+ std::expected<int, MoveOnly> bad(std::unexpect, 99);
+ std::expected<int, long> e3 = std::move(bad).or_else(fun);
+ VERIFY( *e3 == 99 );
+ const auto& badder = bad;
+ std::expected<int, long> e4 = std::move(badder).or_else(fun);
+ VERIFY( *e4 == 99 );
+
+ auto vun = [](const MoveOnly&& mo) { return std::expected<void, long>{}; };
+ std::expected<void, MoveOnly> vud;
+ std::expected<void, long> e5 = std::move(vud).or_else(vun);
+ VERIFY( e5.has_value() );
+ const auto& vudder = vud;
+ std::expected<void, long> e6 = std::move(vudder).or_else(vun);
+ VERIFY( e6.has_value() );
+
+ return true;
+}
+
+static_assert( test_or_else() );
+
+constexpr bool
+test_transform()
+{
+ auto fun = [](int i) { return (long)i; };
+
+ std::expected<int, MoveOnly> good(9);
+ std::expected<long, MoveOnly> e1 = std::move(good).transform(fun);
+ VERIFY( e1 == good );
+ const auto& gooder = good;
+ std::expected<long, MoveOnly> e2 = std::move(gooder).transform(fun);
+ VERIFY( e2 == gooder );
+
+ std::expected<int, MoveOnly> bad(std::unexpect, 99);
+ std::expected<long, MoveOnly> e3 = std::move(bad).transform(fun);
+ VERIFY( e3 == bad );
+ const auto& badder = bad;
+ std::expected<long, MoveOnly> e4 = std::move(badder).transform(fun);
+ VERIFY( e4 == badder );
+
+ auto vun = []() { return 1L; };
+ std::expected<void, MoveOnly> vud;
+ std::expected<long, MoveOnly> e5 = std::move(vud).transform(vun);
+ VERIFY( *e5 == 1 );
+ const auto& vudder = vud;
+ std::expected<long, MoveOnly> e6 = std::move(vudder).transform(vun);
+ VERIFY( *e6 == 1 );
+
+ return true;
+}
+
+static_assert( test_transform() );
+
+constexpr bool
+test_transform_error()
+{
+ auto fun = [](const MoveOnly&& mo) { return (long)mo.i; };
+
+ std::expected<int, MoveOnly> good(9);
+ std::expected<int, long> e1 = std::move(good).transform_error(fun);
+ VERIFY( e1 == good );
+ const auto& gooder = good;
+ std::expected<int, long> e2 = std::move(gooder).transform_error(fun);
+ VERIFY( e2 == gooder );
+
+ std::expected<int, MoveOnly> bad(std::unexpect, 99);
+ std::expected<int, long> e3 = std::move(bad).transform_error(fun);
+ VERIFY( e3.error() == 99 );
+ const auto& badder = bad;
+ std::expected<int, long> e4 = std::move(badder).transform_error(fun);
+ VERIFY( e4.error() == 99 );
+
+ std::expected<void, MoveOnly> vud(std::unexpect, 1);
+ std::expected<void, long> e5 = std::move(vud).transform_error(fun);
+ VERIFY( e5.error() == 1 );
+ const auto& vudder = vud;
+ std::expected<void, long> e6 = std::move(vudder).transform_error(fun);
+ VERIFY( e6.error() == 1 );
+
+ return true;
+}
+
+static_assert( test_transform_error() );