Tested on Linux-X64.

The test adjustments are so that the tests are kept valid, which
required adding a bunch of now-required relops to the test types. The new
transparent-but-non-synthesizing aspects of the relops are tested
separately. The constraints are a valid implementation of the
current Requires-clauses on these operators; I will file an LWG
issue suggesting that such Requires-clauses are instead made
SFINAE-constraints like in this implementation. The rationale
for that being that if such "wrapper types" are supposed to be
"transparent", it would be rather good if they are transparent
for SFINAE-querying for the existence of such relops as well, rather
than always report true and then fail to instantiate.

2016-07-11  Ville Voutilainen  <ville.voutilai...@gmail.com>

    Implement P0307R2, Making Optional Greater Equal Again.
    * include/std/optional (__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.
diff --git a/libstdc++-v3/include/std/optional 
b/libstdc++-v3/include/std/optional
index e9a86a4..1786c2c 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -785,41 +785,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        }
     };
 
+  template<typename _Tp>
+    using __optional_relop_t =
+    enable_if_t<is_constructible<bool, _Tp>::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 +903,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
+    constexpr auto
     operator!=(const optional<_Tp>& __lhs, _Tp const& __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; }
 
   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>
diff --git a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc 
b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc
index 9aa9273..0ce00c1 100644
--- a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/2.cc
@@ -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()
diff --git a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc 
b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc
index 15130d4..d6294ad 100644
--- a/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/constexpr/relops/4.cc
@@ -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()
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/1.cc 
b/libstdc++-v3/testsuite/20_util/optional/relops/1.cc
index 6277032..1315902 100644
--- a/libstdc++-v3/testsuite/20_util/optional/relops/1.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/relops/1.cc
@@ -37,9 +37,25 @@ namespace ns
   { 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()
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/2.cc 
b/libstdc++-v3/testsuite/20_util/optional/relops/2.cc
index 65071c0..1351265 100644
--- a/libstdc++-v3/testsuite/20_util/optional/relops/2.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/relops/2.cc
@@ -37,9 +37,25 @@ namespace ns
   { 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()
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/3.cc 
b/libstdc++-v3/testsuite/20_util/optional/relops/3.cc
index 2fd9e8b..95fde3b 100644
--- a/libstdc++-v3/testsuite/20_util/optional/relops/3.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/relops/3.cc
@@ -37,9 +37,25 @@ namespace ns
   { 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()
diff --git a/libstdc++-v3/testsuite/20_util/optional/relops/4.cc 
b/libstdc++-v3/testsuite/20_util/optional/relops/4.cc
index 363e633..78d0eb8 100644
--- a/libstdc++-v3/testsuite/20_util/optional/relops/4.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/relops/4.cc
@@ -37,9 +37,25 @@ namespace ns
   { 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()
diff --git a/libstdc++-v3/testsuite/20_util/optional/requirements.cc 
b/libstdc++-v3/testsuite/20_util/optional/requirements.cc
index aab572f..d416e59 100644
--- a/libstdc++-v3/testsuite/20_util/optional/requirements.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/requirements.cc
@@ -257,3 +257,73 @@ 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, "");

Reply via email to