public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [v3 PATCH] Implement LWG 2451
@ 2016-07-05 21:45 Ville Voutilainen
  2016-07-06 12:51 ` Jonathan Wakely
  0 siblings, 1 reply; 2+ messages in thread
From: Ville Voutilainen @ 2016-07-05 21:45 UTC (permalink / raw)
  To: gcc-patches, libstdc++

[-- Attachment #1: Type: text/plain, Size: 666 bytes --]

Tested on Linux-x64.

2016-07-05  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.

[-- Attachment #2: lwg2451.diff --]
[-- Type: text/plain, Size: 9855 bytes --]

diff --git a/libstdc++-v3/include/experimental/optional b/libstdc++-v3/include/experimental/optional
index 7524a7e..5657524 100644
--- a/libstdc++-v3/include/experimental/optional
+++ b/libstdc++-v3/include/experimental/optional
@@ -470,6 +470,24 @@ _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<typename std::remove_cv
+            <typename std::remove_reference<_Tp>::type>::type>::type
+    { };
+
+
   /**
     * @brief Class template for optional values.
     */
@@ -502,6 +520,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,
+                typename enable_if<__and_<
+                                     __not_<is_same<_Tp, _Up>>,
+                                     is_constructible<_Tp, _Up&&>,
+                                     is_convertible<_Up&&, _Tp>
+                                     >::value, bool>::type = true>
+      constexpr optional(_Up&& __t)
+        : _Base(_Tp(std::forward<_Up>(__t))) { }
+
+      template <typename _Up,
+                typename enable_if<__and_<
+                                     __not_<is_same<_Tp, _Up>>,
+                                     is_constructible<_Tp, _Up&&>,
+                                     __not_<is_convertible<_Up&&, _Tp>>
+                                     >::value, bool>::type = false>
+      explicit constexpr optional(_Up&& __t)
+        : _Base(_Tp(std::forward<_Up>(__t))) { }
+
+      template <typename _Up,
+                typename enable_if<__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>::type = true>
+      constexpr optional(const optional<_Up>& __t)
+        : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { }
+
+      template <typename _Up,
+                typename enable_if<__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>::type = false>
+      explicit constexpr optional(const optional<_Up>& __t)
+        : _Base(__t ? optional<_Tp>(*__t) : optional<_Tp>()) { }
+
+      template <typename _Up,
+                typename enable_if<__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>::type = true>
+      constexpr optional(optional<_Up>&& __t)
+        : _Base(__t ? optional<_Tp>(std::move(*__t)) : optional<_Tp>()) { }
+
+      template <typename _Up,
+                typename enable_if<__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>::type = 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 +600,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
         return *this;
       }
 
-      template<typename _Up>
-        enable_if_t<is_same<_Tp, decay_t<_Up>>::value, optional&>
+      template<typename _Up,
+               typename enable_if<__and_<
+                                  __not_<is_same<_Up, nullopt_t>>,
+                                  __not_<__is_optional<_Up>>>::value,
+                                  bool>::type = true>
+        optional&
         operator=(_Up&& __u)
         {
           static_assert(__and_<is_constructible<_Tp, _Up>,
@@ -526,6 +620,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
           return *this;
         }
 
+      template<typename _Up,
+               typename enable_if<__and_<
+                                    __not_<is_same<_Tp, _Up>>>::value,
+                                  bool>::type = 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,
+               typename enable_if<__and_<
+                                    __not_<is_same<_Tp, _Up>>>::value,
+                                  bool>::type = 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)
diff --git a/libstdc++-v3/testsuite/experimental/optional/cons/value.cc b/libstdc++-v3/testsuite/experimental/optional/cons/value.cc
index a916951..123a89e 100644
--- a/libstdc++-v3/testsuite/experimental/optional/cons/value.cc
+++ b/libstdc++-v3/testsuite/experimental/optional/cons/value.cc
@@ -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
index 0000000..c862a04
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/optional/cons/value_neg.cc
@@ -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" }
+  }
+}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [v3 PATCH] Implement LWG 2451
  2016-07-05 21:45 [v3 PATCH] Implement LWG 2451 Ville Voutilainen
@ 2016-07-06 12:51 ` Jonathan Wakely
  0 siblings, 0 replies; 2+ messages in thread
From: Jonathan Wakely @ 2016-07-06 12:51 UTC (permalink / raw)
  To: Ville Voutilainen; +Cc: gcc-patches, libstdc++

On 06/07/16 00:44 +0300, Ville Voutilainen wrote:
>    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.

As I mentioned on IRC, experimental::optional is C++14-only so you can
use remove_cv_t and enable_if_t to get rid of some of the typename
X::type clutter.

OK for trunk and gcc-6 with or without that change, your choice.


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2016-07-06 12:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-05 21:45 [v3 PATCH] Implement LWG 2451 Ville Voutilainen
2016-07-06 12:51 ` Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).