diff mbox

[v3] Implement LWG 2509

Message ID CAFk2RUZnAtyUt89mdVPmd7=z3i-GtOmrdR2_jVwQkCapfzS4jA@mail.gmail.com
State New
Headers show

Commit Message

Ville Voutilainen July 5, 2016, 5:33 p.m. UTC
Tested on Linux-X64.

2016-07-05  Ville Voutilainen  <ville.voutilainen@gmail.com>

    Implement LWG 2509,
    any_cast doesn't work with rvalue reference targets and cannot
    move with a value target.
    * include/experimental/any (any(_ValueType&&)): Constrain and
    add an overload that doesn't forward.
    * include/experimental/any (any_cast(any&&)): Constrain and
    add an overload that moves.
    * testsuite/experimental/any/misc/any_cast.cc: Add tests for
    the functionality added by LWG 2509.

Comments

Jonathan Wakely July 5, 2016, 6:15 p.m. UTC | #1
On 05/07/16 20:33 +0300, Ville Voutilainen wrote:
>    Implement LWG 2509,
>    any_cast doesn't work with rvalue reference targets and cannot
>    move with a value target.
>    * include/experimental/any (any(_ValueType&&)): Constrain and
>    add an overload that doesn't forward.
>    * include/experimental/any (any_cast(any&&)): Constrain and
>    add an overload that moves.

Don't repeat the filename for two changes in the same file, it should
be:

    * include/experimental/any (any(_ValueType&&)): Constrain and
    add an overload that doesn't forward.
    (any_cast(any&&)): Constrain and add an overload that moves.


OK with that tweak to the changelog, thanks.
diff mbox

Patch

diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any
index ae40091..96ad576 100644
--- a/libstdc++-v3/include/experimental/any
+++ b/libstdc++-v3/include/experimental/any
@@ -158,7 +158,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
     /// Construct with a copy of @p __value as the contained object.
     template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
-	      typename _Mgr = _Manager<_Tp>>
+	      typename _Mgr = _Manager<_Tp>,
+              typename enable_if<is_constructible<_Tp, _ValueType&&>::value,
+                                 bool>::type = true>
       any(_ValueType&& __value)
       : _M_manager(&_Mgr::_S_manage)
       {
@@ -167,6 +169,19 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 		      "The contained object must be CopyConstructible");
       }
 
+    /// Construct with a copy of @p __value as the contained object.
+    template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
+	      typename _Mgr = _Manager<_Tp>,
+              typename enable_if<!is_constructible<_Tp, _ValueType&&>::value,
+                                 bool>::type = false>
+      any(_ValueType&& __value)
+      : _M_manager(&_Mgr::_S_manage)
+      {
+        _Mgr::_S_create(_M_storage, __value);
+	static_assert(is_copy_constructible<_Tp>::value,
+		      "The contained object must be CopyConstructible");
+      }
+
     /// Destructor, calls @c clear()
     ~any() { clear(); }
 
@@ -377,7 +392,10 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       __throw_bad_any_cast();
     }
 
-  template<typename _ValueType>
+  template<typename _ValueType,
+           typename enable_if<!is_move_constructible<_ValueType>::value
+                              || is_lvalue_reference<_ValueType>::value,
+                              bool>::type = true>
     inline _ValueType any_cast(any&& __any)
     {
       static_assert(any::__is_valid_cast<_ValueType>(),
@@ -387,6 +405,20 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	return *__p;
       __throw_bad_any_cast();
     }
+
+  template<typename _ValueType,
+           typename enable_if<is_move_constructible<_ValueType>::value
+                              && !is_lvalue_reference<_ValueType>::value,
+                              bool>::type = false>
+    inline _ValueType any_cast(any&& __any)
+    {
+      static_assert(any::__is_valid_cast<_ValueType>(),
+	  "Template argument must be a reference or CopyConstructible type");
+      auto __p = any_cast<remove_reference_t<_ValueType>>(&__any);
+      if (__p)
+	return std::move(*__p);
+      __throw_bad_any_cast();
+    }
   // @}
 
   template<typename _Tp>
diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc
index ce3f213..bb0f754 100644
--- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc
+++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc
@@ -77,8 +77,38 @@  void test02()
   }
 }
 
+static int move_count = 0;
+
+void test03()
+{
+  struct MoveEnabled
+  {
+    MoveEnabled(MoveEnabled&&)
+    {
+      ++move_count;
+    }
+    MoveEnabled() = default;
+    MoveEnabled(const MoveEnabled&) = default;
+  };
+  MoveEnabled m;
+  MoveEnabled m2 = any_cast<MoveEnabled>(any(m));
+  VERIFY(move_count == 1);
+  MoveEnabled&& m3 = any_cast<MoveEnabled&&>(any(m));
+  VERIFY(move_count == 1);
+  struct MoveDeleted
+  {
+    MoveDeleted(MoveDeleted&&) = delete;
+    MoveDeleted() = default;
+    MoveDeleted(const MoveDeleted&) = default;
+  };
+  MoveDeleted md;
+  MoveDeleted&& md2 = any_cast<MoveDeleted>(any(std::move(md)));
+  MoveDeleted&& md3 = any_cast<MoveDeleted&&>(any(std::move(md)));
+}
+
 int main()
 {
   test01();
   test02();
+  test03();
 }
diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
index 1361db8..82957a1 100644
--- a/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/experimental/any/misc/any_cast_neg.cc
@@ -26,5 +26,5 @@  void test01()
   using std::experimental::any_cast;
 
   const any y(1);
-  any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 353 }
+  any_cast<int&>(y); // { dg-error "qualifiers" "" { target { *-*-* } } 368 }
 }