From a5e0121b8dcae2b6e1980d46522ab5a03b9a610e Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Fri, 27 May 2011 19:08:18 +0000 Subject: [PATCH] noexcept for . And in the process learned that I had done it wrong for pair's swap. I needed to create an __is_nothrow_swappable::value trait that was smart enought to answer false when __is_swappable::value is false. Otherwise one gets compile-time errors when using pair or tuple of non-swappable types, even if you never try to swap the pair or tuple. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@132204 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/__tuple | 12 +++++----- include/tuple | 57 ++++++++++++++++++++++++++++++++++----------- include/type_traits | 48 ++++++++++++++++++++++++++++++++++++++ include/utility | 34 +++++++++++---------------- 4 files changed, 111 insertions(+), 40 deletions(-) diff --git a/include/__tuple b/include/__tuple index ddd507ca..b5d80e14 100644 --- a/include/__tuple +++ b/include/__tuple @@ -78,27 +78,27 @@ template struct __tuple_like > : tru template typename tuple_element<_Ip, tuple<_Tp...> >::type& -get(tuple<_Tp...>&); +get(tuple<_Tp...>&) _NOEXCEPT; template const typename tuple_element<_Ip, tuple<_Tp...> >::type& -get(const tuple<_Tp...>&); +get(const tuple<_Tp...>&) _NOEXCEPT; template typename tuple_element<_Ip, tuple<_Tp...> >::type&& -get(tuple<_Tp...>&&); +get(tuple<_Tp...>&&) _NOEXCEPT; template typename tuple_element<_Ip, pair<_T1, _T2> >::type& -get(pair<_T1, _T2>&); +get(pair<_T1, _T2>&) _NOEXCEPT; template const typename tuple_element<_Ip, pair<_T1, _T2> >::type& -get(const pair<_T1, _T2>&); +get(const pair<_T1, _T2>&) _NOEXCEPT; template typename tuple_element<_Ip, pair<_T1, _T2> >::type&& -get(pair<_T1, _T2>&&); +get(pair<_T1, _T2>&&) _NOEXCEPT; template _Tp& diff --git a/include/tuple b/include/tuple index 63ce4cc3..49f220d0 100644 --- a/include/tuple +++ b/include/tuple @@ -25,7 +25,7 @@ public: template explicit tuple(U&&...); tuple(const tuple&) = default; - tuple(tuple&&); + tuple(tuple&&) = default; template tuple(const tuple&); template @@ -56,7 +56,8 @@ public: tuple(allocator_arg_t, const Alloc& a, pair&&); tuple& operator=(const tuple&); - tuple& operator=(tuple&&); + tuple& + operator=(tuple&&) noexcept(AND(is_nothrow_move_assignable::value ...)); template tuple& operator=(const tuple&); template @@ -66,14 +67,14 @@ public: template tuple& operator=(pair&&); //iffsizeof...(T) == 2 - void swap(tuple&); + void swap(tuple&) noexcept(AND(swap(declval(), declval())...)); }; const unspecified ignore; template tuple make_tuple(T&&...); -template tuple forward_as_tuple(T&&...); -template tuple tie(T&...); +template tuple forward_as_tuple(T&&...) noexcept; +template tuple tie(T&...) noexcept; template tuple tuple_cat(Tuples&&... tpls); // 20.4.1.4, tuple helper classes: @@ -83,9 +84,15 @@ template class tuple_element; // undefined template class tuple_element>; // 20.4.1.5, element access: -template typename tuple_element>::type& get(tuple&); -template typename tuple_element>::type const& get(const tuple&); -template typename tuple_element>::type&& get(tuple&&); +template + typename tuple_element>::type& + get(tuple&) noexcept; +template + typename tuple_element>::type const& + get(const tuple&) noexcept; +template + typename tuple_element>::type&& + get(tuple&&) noexcept; // 20.4.1.6, relational operators: template bool operator==(const tuple&, const tuple&); @@ -99,7 +106,8 @@ template struct uses_allocator, Alloc>; template - void swap(tuple& x, tuple& y); + void + swap(tuple& x, tuple& y) noexcept(noexcept(x.swap(y))); } // std @@ -142,6 +150,7 @@ class __tuple_leaf; template inline _LIBCPP_INLINE_VISIBILITY void swap(__tuple_leaf<_Ip, _Hp, _Ep>& __x, __tuple_leaf<_Ip, _Hp, _Ep>& __y) + _NOEXCEPT_(__is_nothrow_swappable<_Hp>::value) { swap(__x.get(), __y.get()); } @@ -256,7 +265,7 @@ public: } _LIBCPP_INLINE_VISIBILITY - int swap(__tuple_leaf& __t) + int swap(__tuple_leaf& __t) _NOEXCEPT_(__is_nothrow_swappable<__tuple_leaf>::value) { _STD::swap(*this, __t); return 0; @@ -324,7 +333,9 @@ public: return *this; } - _LIBCPP_INLINE_VISIBILITY int swap(__tuple_leaf& __t) + _LIBCPP_INLINE_VISIBILITY + int + swap(__tuple_leaf& __t) _NOEXCEPT_(__is_nothrow_swappable<__tuple_leaf>::value) { _STD::swap(*this, __t); return 0; @@ -338,6 +349,20 @@ template _LIBCPP_INLINE_VISIBILITY void __swallow(_Tp&&...) {} +template struct __all; + +template <> +struct __all<> +{ + static const bool value = true; +}; + +template +struct __all<_B0, _B...> +{ + static const bool value = _B0 && __all<_B...>::value; +}; + // __tuple_impl template struct __tuple_impl; @@ -412,6 +437,7 @@ struct __tuple_impl<__tuple_indices<_Indx...>, _Tp...> _LIBCPP_INLINE_VISIBILITY void swap(__tuple_impl& __t) + _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) { __swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t))...); } @@ -533,7 +559,8 @@ public: } _LIBCPP_INLINE_VISIBILITY - void swap(tuple& __t) {base_.swap(__t.base_);} + void swap(tuple& __t) _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) + {base_.swap(__t.base_);} }; template <> @@ -555,13 +582,15 @@ public: _LIBCPP_INLINE_VISIBILITY tuple(allocator_arg_t, const _Alloc&, array<_U, 0>) {} _LIBCPP_INLINE_VISIBILITY - void swap(tuple&) {} + void swap(tuple&) _NOEXCEPT {} }; template inline _LIBCPP_INLINE_VISIBILITY void -swap(tuple<_Tp...>& __t, tuple<_Tp...>& __u) {__t.swap(__u);} +swap(tuple<_Tp...>& __t, tuple<_Tp...>& __u) + _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) + {__t.swap(__u);} // get diff --git a/include/type_traits b/include/type_traits index 09f03d7e..40adc273 100644 --- a/include/type_traits +++ b/include/type_traits @@ -3019,6 +3019,54 @@ iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) swap(*__a, *__b); } +// __swappable + +__nat swap(__any, __any); + +template +struct __swappable +{ + typedef decltype(swap(_STD::declval<_Tp&>(), _STD::declval<_Tp&>())) type; + static const bool value = !is_same::value; +}; + +template +struct __is_swappable + : public integral_constant::value> +{ +}; + +#if __has_feature(cxx_noexcept) + +template +struct __is_nothrow_swappable_imp + : public integral_constant(), + _STD::declval<_Tp&>()))> +{ +}; + +template +struct __is_nothrow_swappable_imp + : public false_type +{ +}; + +template +struct __is_nothrow_swappable + : public __is_nothrow_swappable_imp<__is_swappable<_Tp>::value, _Tp> +{ +}; + +#else // __has_feature(cxx_noexcept) + +template +struct __is_nothrow_swappable + : public false_type +{ +}; + +#endif // __has_feature(cxx_noexcept) + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_TYPE_TRAITS diff --git a/include/utility b/include/utility index 1d1b5798..d0ad1ec8 100644 --- a/include/utility +++ b/include/utility @@ -181,8 +181,7 @@ swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardItera template inline _LIBCPP_INLINE_VISIBILITY void -swap(_Tp (&__a)[_N], _Tp (&__b)[_N]) - _NOEXCEPT_(_NOEXCEPT_(swap(_STD::declval<_Tp&>(), _STD::declval<_Tp&>()))) +swap(_Tp (&__a)[_N], _Tp (&__b)[_N]) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) { _STD::swap_ranges(__a, __a + _N, __b); } @@ -311,13 +310,8 @@ struct _LIBCPP_VISIBLE pair #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY void - swap(pair& __p) _NOEXCEPT_( -// _NOEXCEPT_(_STD::iter_swap(&first, &__p.first)) && -// _NOEXCEPT_(_STD::iter_swap(&second, &__p.second))) - _NOEXCEPT_(_STD::iter_swap(&_STD::declval(), - &_STD::declval())) && - _NOEXCEPT_(_STD::iter_swap(&_STD::declval(), - &_STD::declval()))) + swap(pair& __p) _NOEXCEPT_(__is_nothrow_swappable::value && + __is_nothrow_swappable::value) { _STD::iter_swap(&first, &__p.first); _STD::iter_swap(&second, &__p.second); @@ -385,8 +379,8 @@ template inline _LIBCPP_INLINE_VISIBILITY void swap(pair<_T1, _T2>& __x, pair<_T1, _T2>& __y) -// _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) - _NOEXCEPT_(_NOEXCEPT_((_STD::declval&>().swap(_STD::declval&>())))) + _NOEXCEPT_((__is_nothrow_swappable<_T1>::value && + __is_nothrow_swappable<_T2>::value)) { __x.swap(__y); } @@ -481,13 +475,13 @@ struct __get_pair<0> static _LIBCPP_INLINE_VISIBILITY _T1& - get(pair<_T1, _T2>& __p) {return __p.first;} + get(pair<_T1, _T2>& __p) _NOEXCEPT {return __p.first;} template static _LIBCPP_INLINE_VISIBILITY const _T1& - get(const pair<_T1, _T2>& __p) {return __p.first;} + get(const pair<_T1, _T2>& __p) _NOEXCEPT {return __p.first;} #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -495,7 +489,7 @@ struct __get_pair<0> static _LIBCPP_INLINE_VISIBILITY _T1&& - get(pair<_T1, _T2>&& __p) {return _STD::forward<_T1>(__p.first);} + get(pair<_T1, _T2>&& __p) _NOEXCEPT {return _STD::forward<_T1>(__p.first);} #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES }; @@ -507,13 +501,13 @@ struct __get_pair<1> static _LIBCPP_INLINE_VISIBILITY _T2& - get(pair<_T1, _T2>& __p) {return __p.second;} + get(pair<_T1, _T2>& __p) _NOEXCEPT {return __p.second;} template static _LIBCPP_INLINE_VISIBILITY const _T2& - get(const pair<_T1, _T2>& __p) {return __p.second;} + get(const pair<_T1, _T2>& __p) _NOEXCEPT {return __p.second;} #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -521,7 +515,7 @@ struct __get_pair<1> static _LIBCPP_INLINE_VISIBILITY _T2&& - get(pair<_T1, _T2>&& __p) {return _STD::forward<_T2>(__p.second);} + get(pair<_T1, _T2>&& __p) _NOEXCEPT {return _STD::forward<_T2>(__p.second);} #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES }; @@ -529,7 +523,7 @@ struct __get_pair<1> template _LIBCPP_INLINE_VISIBILITY inline typename tuple_element<_Ip, pair<_T1, _T2> >::type& -get(pair<_T1, _T2>& __p) +get(pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } @@ -537,7 +531,7 @@ get(pair<_T1, _T2>& __p) template _LIBCPP_INLINE_VISIBILITY inline const typename tuple_element<_Ip, pair<_T1, _T2> >::type& -get(const pair<_T1, _T2>& __p) +get(const pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } @@ -547,7 +541,7 @@ get(const pair<_T1, _T2>& __p) template _LIBCPP_INLINE_VISIBILITY inline typename tuple_element<_Ip, pair<_T1, _T2> >::type&& -get(pair<_T1, _T2>&& __p) +get(pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(_STD::move(__p)); }