Skip to content

Commit 7524a33

Browse files
committed
optional::value_or return statement is inconsistent with Mandates
LWG4406 https://cplusplus.github.io/LWG/issue4406 Return remove_cv_t<T> and return with `if` rather than ternary expression.
1 parent 8b2f23f commit 7524a33

1 file changed

Lines changed: 28 additions & 13 deletions

File tree

include/beman/optional/optional.hpp

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ class optional {
595595
* @return T
596596
*/
597597
template <class U = std::remove_cv_t<T>>
598-
constexpr T value_or(U&& u) const&;
598+
constexpr std::remove_cv_t<T> value_or(U&& u) const&;
599599
/**
600600
* @brief Returns the contained value if there is one, otherwise returns `u`.
601601
*
@@ -604,7 +604,7 @@ class optional {
604604
* @return T
605605
*/
606606
template <class U = std::remove_cv_t<T>>
607-
constexpr T value_or(U&& u) &&;
607+
constexpr std::remove_cv_t<T> value_or(U&& u) &&;
608608

609609
// \ref{optional.monadic}, monadic operations
610610

@@ -1095,17 +1095,25 @@ inline constexpr T&& optional<T>::value() && {
10951095
/// Returns the contained value if there is one, otherwise returns `u`
10961096
template <class T>
10971097
template <class U>
1098-
inline constexpr T optional<T>::value_or(U&& u) const& {
1099-
static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>);
1100-
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
1098+
inline constexpr std::remove_cv_t<T> optional<T>::value_or(U&& u) const& {
1099+
using X = std::remove_cv_t<T>;
1100+
static_assert(std::is_convertible_v<const T&, X>, "Must be able to convert const T& to remove_cv_t<T>");
1101+
static_assert(std::is_convertible_v<U, X>, "Must be able to convert u to remove_cv_t<T>");
1102+
if (has_value())
1103+
return value_;
1104+
return std::forward<U>(u);
11011105
}
11021106

11031107
template <class T>
11041108
template <class U>
1105-
inline constexpr T optional<T>::value_or(U&& u) && {
1106-
static_assert(std::is_move_constructible_v<T>);
1107-
static_assert(std::is_convertible_v<decltype(u), T>, "Must be able to convert u to T");
1108-
return has_value() ? std::move(value()) : static_cast<T>(std::forward<U>(u));
1109+
inline constexpr std::remove_cv_t<T> optional<T>::value_or(U&& u) && {
1110+
using X = std::remove_cv_t<T>;
1111+
static_assert(std::is_convertible_v<T, X>, "Must be able to convert T to remove_cv_t<T>");
1112+
static_assert(std::is_convertible_v<U, X>, "Must be able to convert u to remove_cv_t<T>");
1113+
if (has_value()) {
1114+
return std::move(value_);
1115+
}
1116+
return std::forward<U>(u);
11091117
}
11101118

11111119
// 22.5.3.8 Monadic operations[optional.monadic]
@@ -1986,15 +1994,22 @@ constexpr bool optional<T&>::has_value() const noexcept {
19861994

19871995
template <class T>
19881996
constexpr T& optional<T&>::value() const {
1989-
return has_value() ? *value_ : throw bad_optional_access();
1997+
if (has_value()) {
1998+
return *value_;
1999+
}
2000+
throw bad_optional_access();
19902001
}
19912002

19922003
template <class T>
19932004
template <class U>
19942005
constexpr std::remove_cv_t<T> optional<T&>::value_or(U&& u) const {
1995-
static_assert(std::is_constructible_v<std::remove_cv_t<T>, T&>, "T must be constructible from a T&");
1996-
static_assert(std::is_convertible_v<U, std::remove_cv_t<T>>, "Must be able to convert u to T");
1997-
return has_value() ? *value_ : static_cast<std::remove_cv_t<T>>(std::forward<U>(u));
2006+
using X = std::remove_cv_t<T>;
2007+
static_assert(std::is_convertible_v<T&, X>, "remove_cv_t<T> must be constructible from a T&");
2008+
static_assert(std::is_convertible_v<U, X>, "Must be able to convert u to remove_cv_t<T>");
2009+
if (has_value()) {
2010+
return *value_;
2011+
}
2012+
return std::forward<U>(u);
19982013
}
19992014

20002015
// \rSec3[optionalref.monadic]{Monadic operations}

0 commit comments

Comments
 (0)