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.

From-SVN: r238292
This commit is contained in:
Ville Voutilainen 2016-07-13 14:25:51 +03:00
parent ceea48fc64
commit 86c0ec1de1
10 changed files with 283 additions and 52 deletions

View File

@ -1,3 +1,42 @@
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):

View File

@ -155,8 +155,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @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

View File

@ -131,8 +131,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* @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
@ -577,16 +577,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
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
@ -597,15 +595,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
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())
@ -621,16 +617,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
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())
@ -785,41 +779,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
};
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>
@ -884,64 +897,76 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// [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>

View File

@ -54,6 +54,18 @@ namespace ns
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()

View File

@ -54,6 +54,18 @@ namespace ns
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()

View File

@ -36,10 +36,26 @@ namespace ns
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()

View File

@ -36,10 +36,26 @@ namespace ns
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()

View File

@ -36,10 +36,26 @@ namespace ns
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()

View File

@ -36,10 +36,26 @@ namespace ns
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()

View File

@ -257,3 +257,82 @@ 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, "");