fix: allow overlapping types in Expected (#5218)

For example, Expected<std::uint32_t, Json::Value>, will now build even though there is animplicit conversion from unsigned int to Json::Value.
This commit is contained in:
Mayukha Vadari
2024-12-16 15:00:14 -08:00
committed by GitHub
parent 5cd72f2431
commit bcbfb04992
2 changed files with 27 additions and 2 deletions

View File

@@ -137,13 +137,15 @@ class [[nodiscard]] Expected
public: public:
template <typename U> template <typename U>
requires std::convertible_to<U, T> requires std::convertible_to<U, T>
constexpr Expected(U&& r) : Base(T(std::forward<U>(r))) constexpr Expected(U&& r)
: Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
{ {
} }
template <typename U> template <typename U>
requires std::convertible_to<U, E> && (!std::is_reference_v<U>) requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
constexpr Expected(Unexpected<U> e) : Base(E(std::move(e.value()))) constexpr Expected(Unexpected<U> e)
: Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
{ {
} }

View File

@@ -84,6 +84,29 @@ struct Expected_test : beast::unit_test::suite
} }
BEAST_EXPECT(throwOccurred); BEAST_EXPECT(throwOccurred);
} }
// Test non-error overlapping type construction.
{
auto expected = []() -> Expected<std::uint32_t, std::uint16_t> {
return 1;
}();
BEAST_EXPECT(expected);
BEAST_EXPECT(expected.has_value());
BEAST_EXPECT(expected.value() == 1);
BEAST_EXPECT(*expected == 1);
bool throwOccurred = false;
try
{
// There's no error, so should throw.
[[maybe_unused]] std::uint16_t const t = expected.error();
}
catch (std::runtime_error const& e)
{
BEAST_EXPECT(e.what() == std::string("bad expected access"));
throwOccurred = true;
}
BEAST_EXPECT(throwOccurred);
}
// Test error construction from rvalue. // Test error construction from rvalue.
{ {
auto const expected = []() -> Expected<std::string, TER> { auto const expected = []() -> Expected<std::string, TER> {