From 7524a33daf1262e013c64d0c3a4ba97b04586197 Mon Sep 17 00:00:00 2001 From: Steve Downey Date: Sat, 22 Nov 2025 16:06:22 -0500 Subject: [PATCH] optional::value_or return statement is inconsistent with Mandates LWG4406 https://cplusplus.github.io/LWG/issue4406 Return remove_cv_t and return with `if` rather than ternary expression. --- include/beman/optional/optional.hpp | 41 ++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/include/beman/optional/optional.hpp b/include/beman/optional/optional.hpp index 4d72548..db33ab8 100644 --- a/include/beman/optional/optional.hpp +++ b/include/beman/optional/optional.hpp @@ -595,7 +595,7 @@ class optional { * @return T */ template > - constexpr T value_or(U&& u) const&; + constexpr std::remove_cv_t value_or(U&& u) const&; /** * @brief Returns the contained value if there is one, otherwise returns `u`. * @@ -604,7 +604,7 @@ class optional { * @return T */ template > - constexpr T value_or(U&& u) &&; + constexpr std::remove_cv_t value_or(U&& u) &&; // \ref{optional.monadic}, monadic operations @@ -1095,17 +1095,25 @@ inline constexpr T&& optional::value() && { /// Returns the contained value if there is one, otherwise returns `u` template template -inline constexpr T optional::value_or(U&& u) const& { - static_assert(std::is_copy_constructible_v && std::is_convertible_v); - return has_value() ? value() : static_cast(std::forward(u)); +inline constexpr std::remove_cv_t optional::value_or(U&& u) const& { + using X = std::remove_cv_t; + static_assert(std::is_convertible_v, "Must be able to convert const T& to remove_cv_t"); + static_assert(std::is_convertible_v, "Must be able to convert u to remove_cv_t"); + if (has_value()) + return value_; + return std::forward(u); } template template -inline constexpr T optional::value_or(U&& u) && { - static_assert(std::is_move_constructible_v); - static_assert(std::is_convertible_v, "Must be able to convert u to T"); - return has_value() ? std::move(value()) : static_cast(std::forward(u)); +inline constexpr std::remove_cv_t optional::value_or(U&& u) && { + using X = std::remove_cv_t; + static_assert(std::is_convertible_v, "Must be able to convert T to remove_cv_t"); + static_assert(std::is_convertible_v, "Must be able to convert u to remove_cv_t"); + if (has_value()) { + return std::move(value_); + } + return std::forward(u); } // 22.5.3.8 Monadic operations[optional.monadic] @@ -1986,15 +1994,22 @@ constexpr bool optional::has_value() const noexcept { template constexpr T& optional::value() const { - return has_value() ? *value_ : throw bad_optional_access(); + if (has_value()) { + return *value_; + } + throw bad_optional_access(); } template template constexpr std::remove_cv_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)); + using X = std::remove_cv_t; + static_assert(std::is_convertible_v, "remove_cv_t must be constructible from a T&"); + static_assert(std::is_convertible_v, "Must be able to convert u to remove_cv_t"); + if (has_value()) { + return *value_; + } + return std::forward(u); } // \rSec3[optionalref.monadic]{Monadic operations}