From 7d4f48b5b85b20df4f1acc19a3f1326d37a8bf6a Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Tue, 5 Jul 2016 21:33:18 +0300 Subject: [PATCH] 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. (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. From-SVN: r238022 --- libstdc++-v3/ChangeLog | 11 ++++++ libstdc++-v3/include/experimental/any | 36 +++++++++++++++++-- .../experimental/any/misc/any_cast.cc | 30 ++++++++++++++++ .../experimental/any/misc/any_cast_neg.cc | 2 +- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 536e49f4311..d888864600e 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2016-07-05 Ville Voutilainen + + 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. + (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. + 2016-07-04 François Dumont * testsuite/23_containers/vector/modifiers/emplace/self_emplace.cc: diff --git a/libstdc++-v3/include/experimental/any b/libstdc++-v3/include/experimental/any index ae40091fbb4..96ad5762f66 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 _Mgr = _Manager<_Tp>> + typename _Mgr = _Manager<_Tp>, + typename enable_if::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 _Mgr = _Manager<_Tp>, + typename enable_if::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 + template::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::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>(&__any); + if (__p) + return std::move(*__p); + __throw_bad_any_cast(); + } // @} template diff --git a/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc b/libstdc++-v3/testsuite/experimental/any/misc/any_cast.cc index ce3f2135889..bb0f754f549 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(any(m)); + VERIFY(move_count == 1); + MoveEnabled&& m3 = any_cast(any(m)); + VERIFY(move_count == 1); + struct MoveDeleted + { + MoveDeleted(MoveDeleted&&) = delete; + MoveDeleted() = default; + MoveDeleted(const MoveDeleted&) = default; + }; + MoveDeleted md; + MoveDeleted&& md2 = any_cast(any(std::move(md))); + MoveDeleted&& md3 = any_cast(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 1361db89d4c..82957a1f544 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(y); // { dg-error "qualifiers" "" { target { *-*-* } } 353 } + any_cast(y); // { dg-error "qualifiers" "" { target { *-*-* } } 368 } }