Tested on Linux-X64. 2016-07-05 Ville Voutilainen <ville.voutilai...@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.
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 } }