* include/experimental/optional (_Has_addressof): Fix the comment.
* include/std/optional (_Has_addressof): Likewise.
(operator=(_Up&&)): Constrain.
(operator=(const optional<_Up>&)): Likewise.
(operator=(optional<_Up>&&)): Likewise.
(__optional_relop_t): New.
(operator==(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
(operator!=(const optional<_Tp>&, const optional<_Tp>&)):
Constrain and make transparent.
(operator<(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
(operator>(const optional<_Tp>&, const optional<_Tp>&)):
Constrain and make transparent.
(operator<=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
(operator>=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
(operator==(const optional<_Tp>&, const _Tp&): Constrain.
(operator==(const _Tp&, const optional<_Tp>&)): Likewise.
(operator!=(const optional<_Tp>&, _Tp const&)):
Constrain and make transparent.
(operator!=(const _Tp&, const optional<_Tp>&)): Likewise.
(operator<(const optional<_Tp>&, const _Tp&)): Constrain.
(operator<(const _Tp&, const optional<_Tp>&)): Likewise.
(operator>(const optional<_Tp>&, const _Tp&)):
Constrain and make transparent.
(operator>(const _Tp&, const optional<_Tp>&)): Likewise.
(operator<=(const optional<_Tp>&, const _Tp&)): Likewise.
(operator<=(const _Tp&, const optional<_Tp>&)): Likewise.
(operator>=(const optional<_Tp>&, const _Tp&)): Likewise.
(operator>=(const _Tp&, const optional<_Tp>&)): Likewise.
* testsuite/20_util/optional/constexpr/relops/2.cc: Adjust.
* testsuite/20_util/optional/constexpr/relops/4.cc: Likewise.
* testsuite/20_util/optional/relops/1.cc: Likewise.
* testsuite/20_util/optional/relops/2.cc: Likewise.
* testsuite/20_util/optional/relops/3.cc: Likewise.
* testsuite/20_util/optional/relops/4.cc: Likewise.
* testsuite/20_util/optional/requirements.cc: Add tests to verify
that optional's relops are transparent and don't synthesize
operators. Also test that assignment sfinaes.
From-SVN: r238292
+ Implement P0307R2, Making Optional Greater Equal Again.
+ * include/experimental/optional (_Has_addressof): Fix the comment.
+ * include/std/optional (_Has_addressof): Likewise.
+ (operator=(_Up&&)): Constrain.
+ (operator=(const optional<_Up>&)): Likewise.
+ (operator=(optional<_Up>&&)): Likewise.
+ (__optional_relop_t): New.
+ (operator==(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
+ (operator!=(const optional<_Tp>&, const optional<_Tp>&)):
+ Constrain and make transparent.
+ (operator<(const optional<_Tp>&, const optional<_Tp>&)): Constrain.
+ (operator>(const optional<_Tp>&, const optional<_Tp>&)):
+ Constrain and make transparent.
+ (operator<=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
+ (operator>=(const optional<_Tp>&, const optional<_Tp>&)): Likewise.
+ (operator==(const optional<_Tp>&, const _Tp&): Constrain.
+ (operator==(const _Tp&, const optional<_Tp>&)): Likewise.
+ (operator!=(const optional<_Tp>&, _Tp const&)):
+ Constrain and make transparent.
+ (operator!=(const _Tp&, const optional<_Tp>&)): Likewise.
+ (operator<(const optional<_Tp>&, const _Tp&)): Constrain.
+ (operator<(const _Tp&, const optional<_Tp>&)): Likewise.
+ (operator>(const optional<_Tp>&, const _Tp&)):
+ Constrain and make transparent.
+ (operator>(const _Tp&, const optional<_Tp>&)): Likewise.
+ (operator<=(const optional<_Tp>&, const _Tp&)): Likewise.
+ (operator<=(const _Tp&, const optional<_Tp>&)): Likewise.
+ (operator>=(const optional<_Tp>&, const _Tp&)): Likewise.
+ (operator>=(const _Tp&, const optional<_Tp>&)): Likewise.
+ * testsuite/20_util/optional/constexpr/relops/2.cc: Adjust.
+ * testsuite/20_util/optional/constexpr/relops/4.cc: Likewise.
+ * testsuite/20_util/optional/relops/1.cc: Likewise.
+ * testsuite/20_util/optional/relops/2.cc: Likewise.
+ * testsuite/20_util/optional/relops/3.cc: Likewise.
+ * testsuite/20_util/optional/relops/4.cc: Likewise.
+ * testsuite/20_util/optional/requirements.cc: Add tests to verify
+ that optional's relops are transparent and don't synthesize
+ operators. Also test that assignment sfinaes.
+
2016-07-13 Jonathan Wakely <jwakely@redhat.com>
* include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI] (_M_c_str):
* @brief Trait that detects the presence of an overloaded unary operator&.
*
* Practically speaking this detects the presence of such an operator when
- * called on a const-qualified lvalue (i.e.
- * declval<_Tp * const&>().operator&()).
+ * called on a const-qualified lvalue (e.g.
+ * declval<const _Tp&>().operator&()).
*/
template<typename _Tp>
struct _Has_addressof
* @brief Trait that detects the presence of an overloaded unary operator&.
*
* Practically speaking this detects the presence of such an operator when
- * called on a const-qualified lvalue (i.e.
- * declval<_Tp * const&>().operator&()).
+ * called on a const-qualified lvalue (e.g.
+ * declval<const _Tp&>().operator&()).
*/
template<typename _Tp>
struct _Has_addressof
template<typename _Up,
enable_if_t<__and_<
+ is_constructible<_Tp, _Up>,
+ is_assignable<_Tp&, _Up>,
__not_<is_same<_Up, nullopt_t>>,
__not_<__is_optional<_Up>>>::value,
bool> = true>
optional&
operator=(_Up&& __u)
{
- static_assert(__and_<is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>>(),
- "Cannot assign to value type from argument");
-
if (this->_M_is_engaged())
this->_M_get() = std::forward<_Up>(__u);
else
template<typename _Up,
enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>>::value,
- bool> = true>
+ is_constructible<_Tp, _Up>,
+ is_assignable<_Tp&, _Up>,
+ __not_<is_same<_Tp, _Up>>>::value,
+ bool> = true>
optional&
operator=(const optional<_Up>& __u)
{
- static_assert(__and_<is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>>(),
- "Cannot assign to value type from argument");
-
if (__u)
{
if (this->_M_is_engaged())
}
template<typename _Up,
- enable_if_t<__and_<
- __not_<is_same<_Tp, _Up>>>::value,
- bool> = true>
+ enable_if_t<__and_<
+ is_constructible<_Tp, _Up>,
+ is_assignable<_Tp&, _Up>,
+ __not_<is_same<_Tp, _Up>>>::value,
+ bool> = true>
optional&
operator=(optional<_Up>&& __u)
{
- static_assert(__and_<is_constructible<_Tp, _Up>,
- is_assignable<_Tp&, _Up>>(),
- "Cannot assign to value type from argument");
-
if (__u)
{
if (this->_M_is_engaged())
}
};
+ template<typename _Tp>
+ using __optional_relop_t =
+ enable_if_t<is_convertible<_Tp, bool>::value, bool>;
+
// [X.Y.8] Comparisons between optional values.
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator==(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
{
return static_cast<bool>(__lhs) == static_cast<bool>(__rhs)
&& (!__lhs || *__lhs == *__rhs);
}
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator!=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
- { return !(__lhs == __rhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
+ {
+ return static_cast<bool>(__lhs) != static_cast<bool>(__rhs)
+ || (static_cast<bool>(__lhs) && *__lhs != *__rhs);
+ }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator<(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
{
return static_cast<bool>(__rhs) && (!__lhs || *__lhs < *__rhs);
}
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator>(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
- { return __rhs < __lhs; }
+ -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
+ {
+ return static_cast<bool>(__lhs) && (!__rhs || *__lhs > *__rhs);
+ }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator<=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
- { return !(__rhs < __lhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
+ {
+ return !__lhs || (static_cast<bool>(__rhs) && *__lhs <= *__rhs);
+ }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator>=(const optional<_Tp>& __lhs, const optional<_Tp>& __rhs)
- { return !(__lhs < __rhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
+ {
+ return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs);
+ }
// [X.Y.9] Comparisons with nullopt.
template<typename _Tp>
// [X.Y.10] Comparisons with value type.
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator==(const optional<_Tp>& __lhs, const _Tp& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
{ return __lhs && *__lhs == __rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator==(const _Tp& __lhs, const optional<_Tp>& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() == declval<_Tp>())>
{ return __rhs && __lhs == *__rhs; }
template<typename _Tp>
- constexpr bool
- operator!=(const optional<_Tp>& __lhs, _Tp const& __rhs)
- { return !__lhs || !(*__lhs == __rhs); }
+ constexpr auto
+ operator!=(const optional<_Tp>& __lhs, const _Tp& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
+ { return !__lhs || *__lhs != __rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator!=(const _Tp& __lhs, const optional<_Tp>& __rhs)
- { return !__rhs || !(__lhs == *__rhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() != declval<_Tp>())>
+ { return !__rhs || __lhs != *__rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator<(const optional<_Tp>& __lhs, const _Tp& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
{ return !__lhs || *__lhs < __rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator<(const _Tp& __lhs, const optional<_Tp>& __rhs)
+ -> __optional_relop_t<decltype(declval<_Tp>() < declval<_Tp>())>
{ return __rhs && __lhs < *__rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator>(const optional<_Tp>& __lhs, const _Tp& __rhs)
- { return __lhs && __rhs < *__lhs; }
+ -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
+ { return __lhs && *__lhs > __rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator>(const _Tp& __lhs, const optional<_Tp>& __rhs)
- { return !__rhs || *__rhs < __lhs; }
+ -> __optional_relop_t<decltype(declval<_Tp>() > declval<_Tp>())>
+ { return !__rhs || __lhs > *__rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator<=(const optional<_Tp>& __lhs, const _Tp& __rhs)
- { return !__lhs || !(__rhs < *__lhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
+ { return !__lhs || *__lhs <= __rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator<=(const _Tp& __lhs, const optional<_Tp>& __rhs)
- { return __rhs && !(*__rhs < __lhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() <= declval<_Tp>())>
+ { return __rhs && __lhs <= *__rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator>=(const optional<_Tp>& __lhs, const _Tp& __rhs)
- { return __lhs && !(*__lhs < __rhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
+ { return __lhs && *__lhs >= __rhs; }
template<typename _Tp>
- constexpr bool
+ constexpr auto
operator>=(const _Tp& __lhs, const optional<_Tp>& __rhs)
- { return !__rhs || !(__lhs < *__rhs); }
+ -> __optional_relop_t<decltype(declval<_Tp>() >= declval<_Tp>())>
+ { return !__rhs || __lhs >= *__rhs; }
// [X.Y.11]
template<typename _Tp>
operator<(value_type const& lhs, value_type const& rhs)
{ return (lhs.i < rhs.i) || (!(rhs.i < lhs.i) && strrel(lhs.s, rhs.s)); }
+ constexpr bool
+ operator>(value_type const& lhs, value_type const& rhs)
+ { return rhs < lhs; }
+
+ constexpr bool
+ operator<=(value_type const& lhs, value_type const& rhs)
+ { return lhs < rhs || lhs == rhs; }
+
+ constexpr bool
+ operator>=(value_type const& lhs, value_type const& rhs)
+ { return lhs > rhs || lhs == rhs; }
+
} // namespace ns
int main()
operator<(value_type const& lhs, value_type const& rhs)
{ return (lhs.i < rhs.i) || (!(rhs.i < lhs.i) && strrel(lhs.s, rhs.s)); }
+ constexpr bool
+ operator>(value_type const& lhs, value_type const& rhs)
+ { return rhs < lhs; }
+
+ constexpr bool
+ operator<=(value_type const& lhs, value_type const& rhs)
+ { return lhs < rhs || lhs == rhs; }
+
+ constexpr bool
+ operator>=(value_type const& lhs, value_type const& rhs)
+ { return lhs > rhs || lhs == rhs; }
+
} // namespace ns
int main()
operator==(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); }
+ bool
+ operator!=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); }
+
bool
operator<(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); }
+ bool
+ operator>(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator<=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator>=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); }
+
} // namespace ns
int main()
operator==(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); }
+ bool
+ operator!=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); }
+
bool
operator<(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); }
+ bool
+ operator>(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator<=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator>=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); }
+
} // namespace ns
int main()
operator==(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); }
+ bool
+ operator!=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); }
+
bool
operator<(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); }
+ bool
+ operator>(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator<=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator>=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); }
+
} // namespace ns
int main()
operator==(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) == std::tie(rhs.i, rhs.s); }
+ bool
+ operator!=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) != std::tie(rhs.i, rhs.s); }
+
bool
operator<(value_type const& lhs, value_type const& rhs)
{ return std::tie(lhs.i, lhs.s) < std::tie(rhs.i, rhs.s); }
+ bool
+ operator>(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) > std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator<=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) <= std::tie(rhs.i, rhs.s); }
+
+ bool
+ operator>=(value_type const& lhs, value_type const& rhs)
+ { return std::tie(lhs.i, lhs.s) >= std::tie(rhs.i, rhs.s); }
+
} // namespace ns
int main()
static_assert( *o == 33, "" );
}
}
+
+using std::void_t;
+using std::declval;
+using std::true_type;
+using std::false_type;
+
+template <class T, class = void>
+struct is_eq_comparable : false_type {};
+template <class T>
+struct is_eq_comparable<T, void_t<decltype(declval<T>() == declval<T>())>>
+: true_type {};
+
+template <class T, class = void>
+struct is_neq_comparable : false_type {};
+template <class T>
+struct is_neq_comparable<T, void_t<decltype(declval<T>() != declval<T>())>>
+: true_type {};
+
+template <class T, class = void>
+struct is_lt_comparable : false_type {};
+template <class T>
+struct is_lt_comparable<T, void_t<decltype(declval<T>() < declval<T>())>>
+: true_type {};
+
+template <class T, class = void>
+struct is_gt_comparable : false_type {};
+template <class T>
+struct is_gt_comparable<T, void_t<decltype(declval<T>() > declval<T>())>>
+: true_type {};
+
+template <class T, class = void>
+struct is_le_comparable : false_type {};
+template <class T>
+struct is_le_comparable<T, void_t<decltype(declval<T>() <= declval<T>())>>
+: true_type {};
+
+template <class T, class = void>
+struct is_ge_comparable : false_type {};
+template <class T>
+struct is_ge_comparable<T, void_t<decltype(declval<T>() >= declval<T>())>>
+: true_type {};
+
+using std::optional;
+
+static_assert(is_eq_comparable<optional<int>>::value, "");
+static_assert(is_neq_comparable<optional<int>>::value, "");
+static_assert(is_lt_comparable<optional<int>>::value, "");
+static_assert(is_gt_comparable<optional<int>>::value, "");
+static_assert(is_le_comparable<optional<int>>::value, "");
+static_assert(is_ge_comparable<optional<int>>::value, "");
+
+struct JustEq {};
+bool operator==(const JustEq&, const JustEq&);
+
+static_assert(is_eq_comparable<optional<JustEq>>::value, "");
+static_assert(!is_neq_comparable<optional<JustEq>>::value, "");
+static_assert(!is_lt_comparable<optional<JustEq>>::value, "");
+static_assert(!is_gt_comparable<optional<JustEq>>::value, "");
+static_assert(!is_le_comparable<optional<JustEq>>::value, "");
+static_assert(!is_ge_comparable<optional<JustEq>>::value, "");
+
+struct JustLt {};
+bool operator<(const JustLt&, const JustLt&);
+
+static_assert(!is_eq_comparable<optional<JustLt>>::value, "");
+static_assert(!is_neq_comparable<optional<JustLt>>::value, "");
+static_assert(is_lt_comparable<optional<JustLt>>::value, "");
+static_assert(!is_gt_comparable<optional<JustLt>>::value, "");
+static_assert(!is_le_comparable<optional<JustLt>>::value, "");
+static_assert(!is_ge_comparable<optional<JustLt>>::value, "");
+
+static_assert(!std::is_assignable<optional<JustEq>&,
+ optional<JustLt>>::value, "");
+static_assert(!std::is_assignable<optional<JustEq>&,
+ JustLt>::value, "");
+static_assert(!std::is_assignable<optional<JustEq>&,
+ optional<JustLt>&>::value, "");
+static_assert(!std::is_assignable<optional<JustEq>&,
+ JustLt&>::value, "");