Skip to content

Commit 78c9abb

Browse files
authored
Merge pull request #148 from steve-downey/LWG4406-value_or
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.
2 parents eb53a48 + 3a8c755 commit 78c9abb

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

include/beman/optional/optional.hpp

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ class optional {
605605
* @return T
606606
*/
607607
template <class U = std::remove_cv_t<T>>
608-
constexpr T value_or(U&& u) const&;
608+
constexpr std::remove_cv_t<T> value_or(U&& u) const&;
609609
/**
610610
* @brief Returns the contained value if there is one, otherwise returns `u`.
611611
*
@@ -614,7 +614,7 @@ class optional {
614614
* @return T
615615
*/
616616
template <class U = std::remove_cv_t<T>>
617-
constexpr T value_or(U&& u) &&;
617+
constexpr std::remove_cv_t<T> value_or(U&& u) &&;
618618

619619
// \ref{optional.monadic}, monadic operations
620620

@@ -1105,17 +1105,25 @@ inline constexpr T&& optional<T>::value() && {
11051105
/// Returns the contained value if there is one, otherwise returns `u`
11061106
template <class T>
11071107
template <class U>
1108-
inline constexpr T optional<T>::value_or(U&& u) const& {
1109-
static_assert(std::is_copy_constructible_v<T> && std::is_convertible_v<U&&, T>);
1110-
return has_value() ? value() : static_cast<T>(std::forward<U>(u));
1108+
inline constexpr std::remove_cv_t<T> optional<T>::value_or(U&& u) const& {
1109+
using X = std::remove_cv_t<T>;
1110+
static_assert(std::is_convertible_v<const T&, X>, "Must be able to convert const T& to remove_cv_t<T>");
1111+
static_assert(std::is_convertible_v<U, X>, "Must be able to convert u to remove_cv_t<T>");
1112+
if (has_value())
1113+
return value_;
1114+
return std::forward<U>(u);
11111115
}
11121116

11131117
template <class T>
11141118
template <class U>
1115-
inline constexpr T optional<T>::value_or(U&& u) && {
1116-
static_assert(std::is_move_constructible_v<T>);
1117-
static_assert(std::is_convertible_v<decltype(u), T>, "Must be able to convert u to T");
1118-
return has_value() ? std::move(value()) : static_cast<T>(std::forward<U>(u));
1119+
inline constexpr std::remove_cv_t<T> optional<T>::value_or(U&& u) && {
1120+
using X = std::remove_cv_t<T>;
1121+
static_assert(std::is_convertible_v<T, X>, "Must be able to convert T to remove_cv_t<T>");
1122+
static_assert(std::is_convertible_v<U, X>, "Must be able to convert u to remove_cv_t<T>");
1123+
if (has_value()) {
1124+
return std::move(value_);
1125+
}
1126+
return std::forward<U>(u);
11191127
}
11201128

11211129
// 22.5.3.8 Monadic operations[optional.monadic]
@@ -1819,7 +1827,7 @@ class optional<T&> {
18191827
* @return std::remove_cv_t<T>
18201828
*/
18211829
template <class U = std::remove_cv_t<T>>
1822-
requires(std::is_object_v<T> && !std::is_array_v<T>)
1830+
requires (std::is_object_v<T> && !std::is_array_v<T>)
18231831
constexpr std::decay_t<T> value_or(U&& u) const;
18241832

18251833
// \ref{optionalref.monadic}, monadic operations
@@ -2007,16 +2015,23 @@ constexpr bool optional<T&>::has_value() const noexcept {
20072015

20082016
template <class T>
20092017
constexpr T& optional<T&>::value() const {
2010-
return has_value() ? *value_ : throw bad_optional_access();
2018+
if (has_value()) {
2019+
return *value_;
2020+
}
2021+
throw bad_optional_access();
20112022
}
20122023

20132024
template <class T>
20142025
template <class U>
2015-
requires(std::is_object_v<T> && !std::is_array_v<T>)
2026+
requires (std::is_object_v<T> && !std::is_array_v<T>)
20162027
constexpr std::decay_t<T> optional<T&>::value_or(U&& u) const {
2017-
static_assert(std::is_constructible_v<std::remove_cv_t<T>, T&>, "T must be constructible from a T&");
2018-
static_assert(std::is_convertible_v<U, std::remove_cv_t<T>>, "Must be able to convert u to T");
2019-
return has_value() ? *value_ : static_cast<std::remove_cv_t<T>>(std::forward<U>(u));
2028+
using X = std::remove_cv_t<T>;
2029+
static_assert(std::is_convertible_v<T&, X>, "remove_cv_t<T> must be constructible from a T&");
2030+
static_assert(std::is_convertible_v<U, X>, "Must be able to convert u to remove_cv_t<T>");
2031+
if (has_value()) {
2032+
return *value_;
2033+
}
2034+
return std::forward<U>(u);
20202035
}
20212036

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

0 commit comments

Comments
 (0)