Implement LWG 2451, optional<T> should 'forward' T's implicit conversions.
authorVille Voutilainen <ville.voutilainen@gmail.com>
Wed, 6 Jul 2016 13:26:10 +0000 (16:26 +0300)
committerVille Voutilainen <ville@gcc.gnu.org>
Wed, 6 Jul 2016 13:26:10 +0000 (16:26 +0300)
Implement LWG 2451, optional<T> should 'forward' T's
implicit conversions.
* include/experimental/optional (__is_optional_impl, __is_optional):
New.
(optional()): Make constexpr and default.
(optional(_Up&&), optional(const optional<_Up>&),
optional(optional<_Up>&& __t): New.
(operator=(_Up&&)): Constrain.
(operator=(const optional<_Up>&), operator=(optional<_Up>&&)): New.
* testsuite/experimental/optional/cons/value.cc:
Add tests for the functionality added by LWG 2451.
* testsuite/experimental/optional/cons/value_neg.cc: New.

From-SVN: r238049

libstdc++-v3/ChangeLog
libstdc++-v3/include/experimental/optional
libstdc++-v3/testsuite/experimental/optional/cons/value.cc
libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc [new file with mode: 0644]

index d888864600e6e07280200c221758d5cc3b5bbe44..46f7f748f650092fcf5290c5a67f4d121d8d169e 100644 (file)
@@ -1,3 +1,18 @@
+2016-07-06  Ville Voutilainen  <ville.voutilainen@gmail.com>
+
+       Implement LWG 2451, optional<T> should 'forward' T's
+       implicit conversions.
+       * include/experimental/optional (__is_optional_impl, __is_optional):
+       New.
+       (optional()): Make constexpr and default.
+       (optional(_Up&&), optional(const optional<_Up>&),
+       optional(optional<_Up>&& __t): New.
+       (operator=(_Up&&)): Constrain.
+       (operator=(const optional<_Up>&), operator=(optional<_Up>&&)): New.
+       * testsuite/experimental/optional/cons/value.cc:
+       Add tests for the functionality added by LWG 2451.
+       * testsuite/experimental/optional/cons/value_neg.cc: New.
+
 2016-07-05  Ville Voutilainen  <ville.voutilainen@gmail.com>
 
        Implement LWG 2509,
index 7524a7e1357db383dc8043199b5f743ec20e66d6..b6425b7d00ef86dedb04e043502b68966f947858 100644 (file)
@@ -470,6 +470,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       bool _M_engaged = false;
     };
 
+  template<typename _Tp>
+  class optional;
+
+  template<typename>
+    struct __is_optional_impl : false_type
+    { };
+
+  template<typename _Tp>
+  struct __is_optional_impl<optional<_Tp>> : true_type
+    { };
+
+  template<typename _Tp>
+    struct __is_optional
+    : public __is_optional_impl<std::remove_cv_t<std::remove_reference_t<_Tp>>>
+    { };
+
+
   /**
     * @brief Class template for optional values.
     */
@@ -502,6 +519,78 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // _Optional_base has the responsibility for construction.
       using _Base::_Base;
 
+      constexpr optional() = default;
+      // Converting constructors for engaged optionals.
+      template <typename _Up,
+                enable_if_t<__and_<
+                             __not_<is_same<_Tp, _Up>>,
+                             is_constructible<_Tp, _Up&&>,
+                             is_convertible<_Up&&, _Tp>
+                             >::value, bool> = true>
+      constexpr optional(_Up&& __t)
+        : _Base(_Tp(std::forward<_Up>(__t))) { }
+
+      template <typename _Up,
+                enable_if_t<__and_<
+                           __not_<is_same<_Tp, _Up>>,
+                           is_constructible<_Tp, _Up&&>,
+                           __not_<is_convertible<_Up&&, _Tp>>
+                           >::value, bool> = false>
+      explicit constexpr optional(_Up&& __t)
+        : _Base(_Tp(std::forward<_Up>(__t))) { }
+
+      template <typename _Up,
+                enable_if_t<__and_<
+                           __not_<is_same<_Tp, _Up>>,
+                           __not_<is_constructible<
+                             _Tp, const optional<_Up>&>>,
+                           __not_<is_convertible<
+                             const optional<_Up>&, _Tp>>,
+                           is_constructible<_Tp, const _Up&>,
+                           is_convertible<const _Up&, _Tp>
+                           >::value, bool> = true>
+      constexpr optional(const optional<_Up>& __t)
+        : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { }
+
+      template <typename _Up,
+                 enable_if_t<__and_<
+                              __not_<is_same<_Tp, _Up>>,
+                              __not_<is_constructible<
+                                       _Tp, const optional<_Up>&>>,
+                              __not_<is_convertible<
+                                const optional<_Up>&, _Tp>>,
+                              is_constructible<_Tp, const _Up&>,
+                              __not_<is_convertible<const _Up&, _Tp>>
+                              >::value, bool> = false>
+      explicit constexpr optional(const optional<_Up>& __t)
+        : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { }
+
+      template <typename _Up,
+                enable_if_t<__and_<
+                             __not_<is_same<_Tp, _Up>>,
+                             __not_<is_constructible<
+                                      _Tp, optional<_Up>&&>>,
+                             __not_<is_convertible<
+                                      optional<_Up>&&, _Tp>>,
+                             is_constructible<_Tp, _Up&&>,
+                             is_convertible<_Up&&, _Tp>
+                             >::value, bool> = true>
+      constexpr optional(optional<_Up>&& __t)
+        : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { }
+
+      template <typename _Up,
+                enable_if_t<__and_<
+                           __not_<is_same<_Tp, _Up>>,
+                           __not_<is_constructible<
+                                    _Tp, optional<_Up>&&>>,
+                           __not_<is_convertible<
+                                    optional<_Up>&&, _Tp>>,
+                           is_constructible<_Tp, _Up&&>,
+                           __not_<is_convertible<_Up&&, _Tp>>
+                           >::value, bool> = false>
+      explicit constexpr optional(optional<_Up>&& __t)
+        : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { }
+
       // [X.Y.4.3] (partly) Assignment.
       optional&
       operator=(nullopt_t) noexcept
@@ -510,8 +599,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         return *this;
       }
 
-      template<typename _Up>
-        enable_if_t<is_same<_Tp, decay_t<_Up>>::value, optional&>
+      template<typename _Up,
+               enable_if_t<__and_<
+                          __not_<is_same<_Up, nullopt_t>>,
+                          __not_<__is_optional<_Up>>>::value,
+                        bool> = true>
+        optional&
         operator=(_Up&& __u)
         {
           static_assert(__and_<is_constructible<_Tp, _Up>,
@@ -526,6 +619,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           return *this;
         }
 
+      template<typename _Up,
+               enable_if_t<__and_<
+                __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())
+                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>>>::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())
+                this->_M_get() = std::move(*__u);
+              else
+                this->_M_construct(std::move(*__u));
+            }
+          else
+            {
+              this->_M_reset();
+            }
+
+          return *this;
+        }
+
       template<typename... _Args>
        void
        emplace(_Args&&... __args)
index a916951b874dce08cd5016b72418a6900eda354f..123a89ede040daf075bcdbfc460d33874d434161 100644 (file)
@@ -22,6 +22,7 @@
 #include <testsuite_hooks.h>
 
 #include <vector>
+#include <string>
 
 struct tracker
 {
@@ -236,4 +237,22 @@ int main()
 
     VERIFY( result == caught );
   }
+
+  {
+    std::experimental::optional<std::string> os = "foo";
+    struct X
+    {
+      explicit X(int) {}
+      X& operator=(int) {return *this;}
+    };
+    std::experimental::optional<X> ox{42};
+    std::experimental::optional<int> oi{42};
+    std::experimental::optional<X> ox2{oi};
+    std::experimental::optional<std::string> os2;
+    os2 = "foo";
+    std::experimental::optional<X> ox3;
+    ox3 = 42;
+    std::experimental::optional<X> ox4;
+    ox4 = oi;
+  }
 }
diff --git a/libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc b/libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc
new file mode 100644 (file)
index 0000000..c862a04
--- /dev/null
@@ -0,0 +1,39 @@
+// { dg-options "-std=gnu++14" }
+// { dg-do compile }
+
+// Copyright (C) 2013-2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a moved_to of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <experimental/optional>
+#include <testsuite_hooks.h>
+
+#include <string>
+#include <memory>
+
+int main()
+{
+  {
+    struct X
+    {
+      explicit X(int) {}
+    };
+    std::experimental::optional<X> ox{42};
+    std::experimental::optional<X> ox2 = 42; // { dg-error "conversion" }
+    std::experimental::optional<std::unique_ptr<int>> oup{new int};
+    std::experimental::optional<std::unique_ptr<int>> oup2 = new int;  // { dg-error "conversion" }
+  }
+}