diff --git a/include/beman/optional/optional.hpp b/include/beman/optional/optional.hpp index 4d72548..e555b1d 100644 --- a/include/beman/optional/optional.hpp +++ b/include/beman/optional/optional.hpp @@ -1791,6 +1791,16 @@ class optional { */ constexpr T& value() const; + // LWG4304. std::optional is ill-formed due to value_o + // Resolution: + // -?- Constraints: T is a non-array object type. + // -?- Remarks: The return type is unspecified if T is an array type or a + // non-object type. [Note ?: This is to avoid the declaration being + // ill-formed. — end note] + // + // Implementer Note: Using decay_t as a detail as it is remove_cv_t for + // non-array objects, and produces a valid type for arrays and functions, + // which are otherwise `required` out. /** * @brief Returns the contained value if there is one, otherwise returns `u`. * @@ -1799,7 +1809,8 @@ class optional { * @return std::remove_cv_t */ template > - constexpr std::remove_cv_t value_or(U&& u) const; + requires(std::is_object_v && !std::is_array_v) + constexpr std::decay_t value_or(U&& u) const; // \ref{optionalref.monadic}, monadic operations /** @@ -1991,7 +2002,8 @@ constexpr T& optional::value() const { template template -constexpr std::remove_cv_t optional::value_or(U&& u) const { + requires(std::is_object_v && !std::is_array_v) +constexpr std::decay_t optional::value_or(U&& u) const { static_assert(std::is_constructible_v, T&>, "T must be constructible from a T&"); static_assert(std::is_convertible_v>, "Must be able to convert u to T"); return has_value() ? *value_ : static_cast>(std::forward(u)); diff --git a/tests/beman/optional/optional_ref.test.cpp b/tests/beman/optional/optional_ref.test.cpp index 321c035..8c02519 100644 --- a/tests/beman/optional/optional_ref.test.cpp +++ b/tests/beman/optional/optional_ref.test.cpp @@ -864,6 +864,29 @@ TEST(OptionalRefTest, OverloadResolutionChecksDangling) { // static_assert(std::is_same_v); } +namespace { +int int_func(void) { return 7; } +} // namespace + +TEST(OptionalRefTest, NonReturnableRef) { + using IntArray5 = int[5]; + beman::optional::optional o1; + IntArray5 array; + beman::optional::optional o2{array}; + EXPECT_FALSE(o1.has_value()); + EXPECT_TRUE(o2.has_value()); + // value_or removed for array types + // IntArray5 array2; + // auto t1 = o1.value_or(array2); + // auto t2 = o2.value_or(array2); + + using IntFunc = int(void); + beman::optional::optional o3; + beman::optional::optional o4{int_func}; + EXPECT_FALSE(o3.has_value()); + EXPECT_TRUE(o4.has_value()); +} + // beman::optional::optional foo() { // beman::optional::optional o(10); // return o; // Thanks to a simpler implicit move.