diff mbox series

Refactor std::optional SFINAE constraints

Message ID 20180820121309.GA15220@redhat.com
State New
Headers show
Series Refactor std::optional SFINAE constraints | expand

Commit Message

Jonathan Wakely Aug. 20, 2018, 12:13 p.m. UTC
* include/std/optional (_Optional_payload): Use variable templates
	for conditions in default template arguments and exception
	specifications.
	(optional): Likewise. Adjust indentation.
	(optional::__not_self, optional::__not_tag, optional::_Requires): New
	SFINAE helpers.
	(optional::optional): Use new helpers in constructor constraints.
	* include/std/type_traits (__or_v, __and_v): New variable templates.
	* testsuite/20_util/optional/cons/value_neg.cc: Change dg-error to
	dg-prune-output. Remove unused header.

Tested x86_64-linux, committed to trunk.
commit 18f1aa19fe0560b7fa3a352cc0ae86e638f29673
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Aug 20 12:20:10 2018 +0100

    Refactor std::optional SFINAE constraints
    
            * include/std/optional (_Optional_payload): Use variable templates
            for conditions in default template arguments and exception
            specifications.
            (optional): Likewise. Adjust indentation.
            (optional::__not_self, optional::__not_tag, optional::_Requires): New
            SFINAE helpers.
            (optional::optional): Use new helpers in constructor constraints.
            * include/std/type_traits (__or_v, __and_v): New variable templates.
            * testsuite/20_util/optional/cons/value_neg.cc: Change dg-error to
            dg-prune-output. Remove unused header.
diff mbox series

Patch

diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index 746ee2fd87e..d0257c07e1f 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -102,11 +102,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   // Payload for optionals with non-trivial destructor.
   template <typename _Tp,
 	    bool /*_HasTrivialDestructor*/ =
-	      is_trivially_destructible<_Tp>::value,
+	      is_trivially_destructible_v<_Tp>,
 	    bool /*_HasTrivialCopyAssignment*/ =
-	      is_trivially_copy_assignable<_Tp>::value,
+	      is_trivially_copy_assignable_v<_Tp>,
 	    bool /*_HasTrivialMoveAssignment*/ =
-	      is_trivially_move_assignable<_Tp>::value>
+	      is_trivially_move_assignable_v<_Tp>>
     struct _Optional_payload
     {
       constexpr _Optional_payload() noexcept : _M_empty() { }
@@ -165,8 +165,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Optional_payload&
       operator=(_Optional_payload&& __other)
-      noexcept(__and_<is_nothrow_move_constructible<_Tp>,
-		      is_nothrow_move_assignable<_Tp>>())
+      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
+		       is_nothrow_move_assignable<_Tp>>)
       {
 	if (this->_M_engaged && __other._M_engaged)
 	  this->_M_get() = std::move(__other._M_get());
@@ -199,7 +199,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Args>
         void
         _M_construct(_Args&&... __args)
-        noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+        noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
         {
           ::new ((void *) std::__addressof(this->_M_payload))
             _Stored_type(std::forward<_Args>(__args)...);
@@ -377,7 +377,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Args>
         void
         _M_construct(_Args&&... __args)
-        noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+        noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
         {
           ::new ((void *) std::__addressof(this->_M_payload))
             _Stored_type(std::forward<_Args>(__args)...);
@@ -468,8 +468,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Optional_payload&
       operator=(_Optional_payload&& __other)
-      noexcept(__and_<is_nothrow_move_constructible<_Tp>,
-		      is_nothrow_move_assignable<_Tp>>())
+      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
+		       is_nothrow_move_assignable<_Tp>>)
       {
 	if (this->_M_engaged && __other._M_engaged)
 	  this->_M_get() = std::move(__other._M_get());
@@ -496,7 +496,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Args>
         void
         _M_construct(_Args&&... __args)
-        noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+        noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
         {
           ::new ((void *) std::__addressof(this->_M_payload))
             _Stored_type(std::forward<_Args>(__args)...);
@@ -598,8 +598,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Optional_payload&
       operator=(_Optional_payload&& __other)
-      noexcept(__and_<is_nothrow_move_constructible<_Tp>,
-		      is_nothrow_move_assignable<_Tp>>())
+      noexcept(__and_v<is_nothrow_move_constructible<_Tp>,
+		       is_nothrow_move_assignable<_Tp>>)
       {
 	if (this->_M_engaged && __other._M_engaged)
 	  this->_M_get() = std::move(__other._M_get());
@@ -626,7 +626,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Args>
         void
         _M_construct(_Args&&... __args)
-        noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+        noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
         {
           ::new ((void *) std::__addressof(this->_M_payload))
             _Stored_type(std::forward<_Args>(__args)...);
@@ -665,7 +665,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       template<typename... _Args>
 	void
 	_M_construct(_Args&&... __args)
-	noexcept(is_nothrow_constructible<_Stored_type, _Args...>())
+	noexcept(is_nothrow_constructible_v<_Stored_type, _Args...>)
 	{
 	  ::new
 	    (std::__addressof(static_cast<_Dp*>(this)->_M_payload._M_payload))
@@ -735,7 +735,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { }
 
       constexpr _Optional_base(_Optional_base&& __other)
-      noexcept(is_nothrow_move_constructible<_Tp>())
+      noexcept(is_nothrow_move_constructible_v<_Tp>)
 	: _M_payload(__other._M_payload._M_engaged,
 		     std::move(__other._M_payload))
       { }
@@ -864,7 +864,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr _Optional_base(const _Optional_base& __other) = default;
 
       constexpr _Optional_base(_Optional_base&& __other)
-      noexcept(is_nothrow_move_constructible<_Tp>())
+      noexcept(is_nothrow_move_constructible_v<_Tp>)
 	: _M_payload(__other._M_payload._M_engaged,
 		     std::move(__other._M_payload))
       { }
@@ -985,16 +985,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     class optional
     : private _Optional_base<_Tp>,
       private _Enable_copy_move<
-        // Copy constructor.
-        is_copy_constructible<_Tp>::value,
-        // Copy assignment.
-        __and_<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>::value,
-        // Move constructor.
-        is_move_constructible<_Tp>::value,
-        // Move assignment.
-        __and_<is_move_constructible<_Tp>, is_move_assignable<_Tp>>::value,
-        // Unique tag type.
-        optional<_Tp>>
+	// Copy constructor.
+	is_copy_constructible_v<_Tp>,
+	// Copy assignment.
+	__and_v<is_copy_constructible<_Tp>, is_copy_assignable<_Tp>>,
+	// Move constructor.
+	is_move_constructible_v<_Tp>,
+	// Move assignment.
+	__and_v<is_move_constructible<_Tp>, is_move_assignable<_Tp>>,
+	// Unique tag type.
+	optional<_Tp>>
     {
       static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>);
       static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>);
@@ -1003,6 +1003,14 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     private:
       using _Base = _Optional_base<_Tp>;
 
+      // SFINAE helpers
+      template<typename _Up>
+	using __not_self = __not_<is_same<optional, __remove_cvref_t<_Up>>>;
+      template<typename _Up>
+	using __not_tag = __not_<is_same<in_place_t, __remove_cvref_t<_Up>>>;
+      template<typename... _Cond>
+	using _Requires = enable_if_t<__and_v<_Cond...>, bool>;
+
     public:
       using value_type = _Tp;
 
@@ -1011,171 +1019,158 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr optional(nullopt_t) noexcept { }
 
       // Converting constructors for engaged optionals.
-      template <typename _Up = _Tp,
-                enable_if_t<__and_<
-			      __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
-			      __not_<is_same<in_place_t, decay_t<_Up>>>,
-			      is_constructible<_Tp, _Up&&>,
-			      is_convertible<_Up&&, _Tp>
-			      >::value, bool> = true>
-      constexpr optional(_Up&& __t)
+      template<typename _Up = _Tp,
+	       _Requires<__not_self<_Up>, __not_tag<_Up>,
+			 is_constructible<_Tp, _Up&&>,
+			 is_convertible<_Up&&, _Tp>> = true>
+	constexpr
+	optional(_Up&& __t)
+	: _Base(std::in_place, std::forward<_Up>(__t)) { }
+
+      template<typename _Up = _Tp,
+	       _Requires<__not_self<_Up>, __not_tag<_Up>,
+			 is_constructible<_Tp, _Up&&>,
+			 __not_<is_convertible<_Up&&, _Tp>>> = false>
+	explicit constexpr
+	optional(_Up&& __t)
         : _Base(std::in_place, std::forward<_Up>(__t)) { }
 
-      template <typename _Up = _Tp,
-                enable_if_t<__and_<
-			      __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
-			      __not_<is_same<in_place_t, decay_t<_Up>>>,
-			      is_constructible<_Tp, _Up&&>,
-			      __not_<is_convertible<_Up&&, _Tp>>
-			      >::value, bool> = false>
-      explicit constexpr optional(_Up&& __t)
-        : _Base(std::in_place, std::forward<_Up>(__t)) { }
+      template<typename _Up,
+	       _Requires<__not_<is_same<_Tp, _Up>>,
+			 is_constructible<_Tp, const _Up&>,
+			 is_convertible<const _Up&, _Tp>,
+			 __not_<__converts_from_optional<_Tp, _Up>>> = true>
+	constexpr
+	optional(const optional<_Up>& __t)
+	{
+	  if (__t)
+	    emplace(*__t);
+	}
+
+      template<typename _Up,
+	       _Requires<__not_<is_same<_Tp, _Up>>,
+			 is_constructible<_Tp, const _Up&>,
+			 __not_<is_convertible<const _Up&, _Tp>>,
+			 __not_<__converts_from_optional<_Tp, _Up>>> = false>
+	explicit constexpr
+	optional(const optional<_Up>& __t)
+	{
+	  if (__t)
+	    emplace(*__t);
+	}
 
       template <typename _Up,
-                enable_if_t<__and_<
-			    __not_<is_same<_Tp, _Up>>,
-			    is_constructible<_Tp, const _Up&>,
-			    is_convertible<const _Up&, _Tp>,
-			    __not_<__converts_from_optional<_Tp, _Up>>
-			    >::value, bool> = true>
-      constexpr optional(const optional<_Up>& __t)
-      {
-	if (__t)
-	  emplace(*__t);
-      }
+		_Requires<__not_<is_same<_Tp, _Up>>,
+			  is_constructible<_Tp, _Up&&>,
+			  is_convertible<_Up&&, _Tp>,
+			  __not_<__converts_from_optional<_Tp, _Up>>> = true>
+	constexpr
+	optional(optional<_Up>&& __t)
+	{
+	  if (__t)
+	    emplace(std::move(*__t));
+	}
 
       template <typename _Up,
-                 enable_if_t<__and_<
-			       __not_<is_same<_Tp, _Up>>,
-			       is_constructible<_Tp, const _Up&>,
-			       __not_<is_convertible<const _Up&, _Tp>>,
-			       __not_<__converts_from_optional<_Tp, _Up>>
-			       >::value, bool> = false>
-      explicit constexpr optional(const optional<_Up>& __t)
-      {
-	if (__t)
-	  emplace(*__t);
-      }
-
-      template <typename _Up,
-                enable_if_t<__and_<
-			      __not_<is_same<_Tp, _Up>>,
-			      is_constructible<_Tp, _Up&&>,
-			      is_convertible<_Up&&, _Tp>,
-			      __not_<__converts_from_optional<_Tp, _Up>>
-			      >::value, bool> = true>
-      constexpr optional(optional<_Up>&& __t)
-      {
-	if (__t)
-	  emplace(std::move(*__t));
-      }
-
-      template <typename _Up,
-                enable_if_t<__and_<
-			    __not_<is_same<_Tp, _Up>>,
-			    is_constructible<_Tp, _Up&&>,
-			    __not_<is_convertible<_Up&&, _Tp>>,
-			    __not_<__converts_from_optional<_Tp, _Up>>
-			    >::value, bool> = false>
-      explicit constexpr optional(optional<_Up>&& __t)
-      {
-	if (__t)
-	  emplace(std::move(*__t));
-      }
+		_Requires<__not_<is_same<_Tp, _Up>>,
+			  is_constructible<_Tp, _Up&&>,
+			  __not_<is_convertible<_Up&&, _Tp>>,
+			  __not_<__converts_from_optional<_Tp, _Up>>> = false>
+	explicit constexpr
+	optional(optional<_Up>&& __t)
+	{
+	  if (__t)
+	    emplace(std::move(*__t));
+	}
 
       template<typename... _Args,
-	       enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
-      explicit constexpr optional(in_place_t, _Args&&... __args)
-        : _Base(std::in_place, std::forward<_Args>(__args)...) { }
+	       _Requires<is_constructible<_Tp, _Args&&...>> = false>
+	explicit constexpr
+	optional(in_place_t, _Args&&... __args)
+	: _Base(std::in_place, std::forward<_Args>(__args)...) { }
 
       template<typename _Up, typename... _Args,
-               enable_if_t<is_constructible_v<_Tp,
-					      initializer_list<_Up>&,
-					      _Args&&...>, bool> = false>
-      explicit constexpr optional(in_place_t,
-				  initializer_list<_Up> __il,
-				  _Args&&... __args)
-        : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
+	       _Requires<is_constructible<_Tp,
+					  initializer_list<_Up>&,
+					  _Args&&...>> = false>
+	explicit constexpr
+	optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
+	: _Base(std::in_place, __il, std::forward<_Args>(__args)...) { }
 
       // Assignment operators.
       optional&
       operator=(nullopt_t) noexcept
       {
-        this->_M_reset();
-        return *this;
+	this->_M_reset();
+	return *this;
       }
 
       template<typename _Up = _Tp>
-        enable_if_t<__and_<
-		      __not_<is_same<optional<_Tp>, decay_t<_Up>>>,
-		      is_constructible<_Tp, _Up>,
-		      __not_<__and_<is_scalar<_Tp>,
-				    is_same<_Tp, decay_t<_Up>>>>,
-		      is_assignable<_Tp&, _Up>>::value,
+	enable_if_t<__and_v<__not_self<_Up>,
+			    __not_<__and_<is_scalar<_Tp>,
+					  is_same<_Tp, decay_t<_Up>>>>,
+			    is_constructible<_Tp, _Up>,
+			    is_assignable<_Tp&, _Up>>,
 		    optional&>
-        operator=(_Up&& __u)
-        {
-          if (this->_M_is_engaged())
-            this->_M_get() = std::forward<_Up>(__u);
-          else
-            this->_M_construct(std::forward<_Up>(__u));
+	operator=(_Up&& __u)
+	{
+	  if (this->_M_is_engaged())
+	    this->_M_get() = std::forward<_Up>(__u);
+	  else
+	    this->_M_construct(std::forward<_Up>(__u));
 
-          return *this;
-        }
+	  return *this;
+	}
 
       template<typename _Up>
-	enable_if_t<__and_<
-		      __not_<is_same<_Tp, _Up>>,
-		      is_constructible<_Tp, const _Up&>,
-		      is_assignable<_Tp&, _Up>,
-		      __not_<__converts_from_optional<_Tp, _Up>>,
-		      __not_<__assigns_from_optional<_Tp, _Up>>
-		      >::value,
+	enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
+			    is_constructible<_Tp, const _Up&>,
+			    is_assignable<_Tp&, _Up>,
+			    __not_<__converts_from_optional<_Tp, _Up>>,
+			    __not_<__assigns_from_optional<_Tp, _Up>>>,
 		    optional&>
-        operator=(const optional<_Up>& __u)
-        {
-          if (__u)
-            {
-              if (this->_M_is_engaged())
-                this->_M_get() = *__u;
-              else
-                this->_M_construct(*__u);
-            }
-          else
-            {
-              this->_M_reset();
-            }
-          return *this;
-        }
+	operator=(const optional<_Up>& __u)
+	{
+	  if (__u)
+	    {
+	      if (this->_M_is_engaged())
+		this->_M_get() = *__u;
+	      else
+		this->_M_construct(*__u);
+	    }
+	  else
+	    {
+	      this->_M_reset();
+	    }
+	  return *this;
+	}
 
       template<typename _Up>
-	enable_if_t<__and_<
-		      __not_<is_same<_Tp, _Up>>,
-		      is_constructible<_Tp, _Up>,
-		      is_assignable<_Tp&, _Up>,
-		      __not_<__converts_from_optional<_Tp, _Up>>,
-		      __not_<__assigns_from_optional<_Tp, _Up>>
-		      >::value,
+        enable_if_t<__and_v<__not_<is_same<_Tp, _Up>>,
+			    is_constructible<_Tp, _Up>,
+			    is_assignable<_Tp&, _Up>,
+			    __not_<__converts_from_optional<_Tp, _Up>>,
+			    __not_<__assigns_from_optional<_Tp, _Up>>>,
 		    optional&>
-        operator=(optional<_Up>&& __u)
-        {
-          if (__u)
-            {
-              if (this->_M_is_engaged())
-                this->_M_get() = std::move(*__u);
-              else
-                this->_M_construct(std::move(*__u));
-            }
-          else
-            {
-              this->_M_reset();
-            }
+	operator=(optional<_Up>&& __u)
+	{
+	  if (__u)
+	    {
+	      if (this->_M_is_engaged())
+		this->_M_get() = std::move(*__u);
+	      else
+		this->_M_construct(std::move(*__u));
+	    }
+	  else
+	    {
+	      this->_M_reset();
+	    }
 
-          return *this;
-        }
+	  return *this;
+	}
 
       template<typename... _Args>
-	enable_if_t<is_constructible<_Tp, _Args&&...>::value, _Tp&>
+	enable_if_t<is_constructible_v<_Tp, _Args&&...>, _Tp&>
 	emplace(_Args&&... __args)
 	{
 	  this->_M_reset();
@@ -1184,8 +1179,8 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	}
 
       template<typename _Up, typename... _Args>
-	enable_if_t<is_constructible<_Tp, initializer_list<_Up>&,
-				     _Args&&...>::value, _Tp&>
+	enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&,
+				       _Args&&...>, _Tp&>
 	emplace(initializer_list<_Up> __il, _Args&&... __args)
 	{
 	  this->_M_reset();
@@ -1198,19 +1193,19 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Swap.
       void
       swap(optional& __other)
-      noexcept(is_nothrow_move_constructible<_Tp>()
-               && is_nothrow_swappable_v<_Tp>)
+      noexcept(is_nothrow_move_constructible_v<_Tp>
+	       && is_nothrow_swappable_v<_Tp>)
       {
-        using std::swap;
+	using std::swap;
 
-        if (this->_M_is_engaged() && __other._M_is_engaged())
-          swap(this->_M_get(), __other._M_get());
-        else if (this->_M_is_engaged())
+	if (this->_M_is_engaged() && __other._M_is_engaged())
+	  swap(this->_M_get(), __other._M_get());
+	else if (this->_M_is_engaged())
 	  {
 	    __other._M_construct(std::move(this->_M_get()));
 	    this->_M_destruct();
 	  }
-        else if (__other._M_is_engaged())
+	else if (__other._M_is_engaged())
 	  {
 	    this->_M_construct(std::move(__other._M_get()));
 	    __other._M_destruct();
@@ -1307,12 +1302,13 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    ? std::move(this->_M_get())
 	    : static_cast<_Tp>(std::forward<_Up>(__u));
 	}
+
       void reset() noexcept { this->_M_reset(); }
     };
 
   template<typename _Tp>
     using __optional_relop_t =
-    enable_if_t<is_convertible<_Tp, bool>::value, bool>;
+      enable_if_t<is_convertible<_Tp, bool>::value, bool>;
 
   // Comparisons between optional values.
   template<typename _Tp, typename _Up>
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 4f89723d468..86b58ccf225 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -144,6 +144,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 #if __cplusplus >= 201703L
 
+  template<typename... _Bn>
+    inline constexpr bool __or_v = __or_<_Bn...>::value;
+  template<typename... _Bn>
+    inline constexpr bool __and_v = __and_<_Bn...>::value;
+
 #define __cpp_lib_logical_traits 201510
 
   template<typename... _Bn>
diff --git a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
index e9171ef7cc2..020cb26453f 100644
--- a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
@@ -19,8 +19,6 @@ 
 // <http://www.gnu.org/licenses/>.
 
 #include <optional>
-#include <testsuite_hooks.h>
-
 #include <string>
 #include <memory>
 
@@ -37,8 +35,6 @@  int main()
     std::optional<std::unique_ptr<int>> oup2 = new int;  // { dg-error "conversion" }
     struct U { explicit U(std::in_place_t); };
     std::optional<U> ou(std::in_place); // { dg-error "no matching" }
-    // { dg-error "no type" "" { target { *-*-* } } 1020 }
-    // { dg-error "no type" "" { target { *-*-* } } 1030 }
-    // { dg-error "no type" "" { target { *-*-* } } 1087 }
   }
 }
+// { dg-prune-output "no type .*enable_if" }