diff mbox

[v3] Implement LWG 2842, in_place_t check for optional::optional(U&&) should decay U.

Message ID CAFk2RUZebOh5dfQ=2+XUOTwc3djz8wW32ZEvWKGy2BL43+QhyQ@mail.gmail.com
State New
Headers show

Commit Message

Ville Voutilainen Dec. 19, 2016, 2:07 p.m. UTC
Tested on Linux-x64.

The perfect forwarder needs to sfinae out of the way of the in_place_t
signature,
and the in_place_t signature needs to check is_constructible. I also
did some housekeeping
to get rid of the int-pack constraints, because in case of empty packs
it's unclear
what a compiler is supposed to do for them.

2016-12-19  Ville Voutilainen  <ville.voutilainen@gmail.com>

    Implement LWG 2842, in_place_t check for optional::optional(U&&)
    should decay U.
    * include/std/optional (_Optional_base(in_place_t, _Args&&...)):
    Constrain.
    (_Optional_base(in_place_t, initializer_list<_Up>, _Args&&...)):
    Turn the int-pack constraint hack into a saner bool.
    (_Optional_base<_Tp, false>::_Optional_base(in_place_t, _Args&&...)):
    Constrain.
    (_Optional_base<_Tp, false>::_Optional_base(in_place_t,
    initializer_list<_Up>, _Args&&...)):
    Turn the int-pack constraint hack into a saner bool.
    (optional(_Up&&)): Constrain against in_place_t.
    (optional(in_place_t, _Args&&...)): Constrain.
    (constexpr optional(in_place_t, initializer_list<_Up>, _Args&&...)):
    Turn the int-pack constraint hack into a saner bool.
    * testsuite/20_util/optional/cons/value_neg.cc: Add a test for
    a type that is constructible from in_place.

Comments

Jonathan Wakely Dec. 22, 2016, 4:52 p.m. UTC | #1
On 19/12/16 16:07 +0200, Ville Voutilainen wrote:
>Tested on Linux-x64.
>
>The perfect forwarder needs to sfinae out of the way of the in_place_t
>signature,
>and the in_place_t signature needs to check is_constructible. I also
>did some housekeeping
>to get rid of the int-pack constraints, because in case of empty packs
>it's unclear
>what a compiler is supposed to do for them.

OK for trunk.
diff mbox

Patch

diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index 3d69e10..73bc2b4 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -128,15 +128,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       : _Optional_base{} { }
 
       // Constructors for engaged optionals.
-      template<typename... _Args>
+      template<typename... _Args,
+	       enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
         constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
         : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
 
       template<typename _Up, typename... _Args,
-               enable_if_t<is_constructible<_Tp,
-                                            initializer_list<_Up>&,
-                                            _Args&&...>::value,
-                           int>...>
+               enable_if_t<is_constructible_v<_Tp,
+					      initializer_list<_Up>&,
+					      _Args&&...>, bool> = false>
         constexpr explicit _Optional_base(in_place_t,
                                           initializer_list<_Up> __il,
                                           _Args&&... __args)
@@ -264,15 +264,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr _Optional_base(nullopt_t) noexcept
       : _Optional_base{} { }
 
-      template<typename... _Args>
+      template<typename... _Args,
+	       enable_if_t<is_constructible_v<_Tp, _Args&&...>, bool> = false>
         constexpr explicit _Optional_base(in_place_t, _Args&&... __args)
         : _M_payload(std::forward<_Args>(__args)...), _M_engaged(true) { }
 
       template<typename _Up, typename... _Args,
-               enable_if_t<is_constructible<_Tp,
-                                            initializer_list<_Up>&,
-                                            _Args&&...>::value,
-			   int>...>
+               enable_if_t<is_constructible_v<_Tp,
+					      initializer_list<_Up>&,
+					      _Args&&...>, bool> = false>
         constexpr explicit _Optional_base(in_place_t,
                                           initializer_list<_Up> __il,
                                           _Args&&... __args)
@@ -432,6 +432,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       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>
@@ -441,6 +442,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       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>
@@ -499,15 +501,15 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  emplace(std::move(*__t));
       }
 
-      template<typename... _Args>
+      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)...) { }
 
       template<typename _Up, typename... _Args,
-               enable_if_t<is_constructible<_Tp,
-                                            initializer_list<_Up>&,
-                                            _Args&&...>::value,
-                           int>...>
+               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)
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 21e86c5..6a2827e 100644
--- a/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/cons/value_neg.cc
@@ -35,5 +35,10 @@  int main()
     std::optional<X> ox2 = 42; // { dg-error "conversion" }
     std::optional<std::unique_ptr<int>> oup{new int};
     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 { *-*-* } } 438 }
+    // { dg-error "no type" "" { target { *-*-* } } 448 }
+    // { dg-error "no type" "" { target { *-*-* } } 505 }
   }
 }