+2016-10-20 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/backward/auto_ptr.h (__shared_ptr(auto_ptr&&))
+ (shared_ptr(auto_ptr&&)): Adjust template parameter lists.
+ * include/bits/shared_ptr.h (__sp_compatible_with)
+ (__sp_is_constructible): New helper traits for shared_ptr.
+ (shared_ptr::_Convertible): Replace with _Constructible.
+ (shared_ptr::_Constructible, shared_ptr::_Assignable): Forward checks
+ to base class.
+ (shared_ptr::shared_ptr, shared_ptr::operator=): Constrain template
+ with _Constructible and _Assignable.
+ (shared_ptr::shared_ptr(shared_ptr<_Tp1>, _Tp*)): Use element_type
+ instead of _Tp.
+ (operator<): Likewise.
+ (operator>): Define in terms of operator<.
+ (static_pointer_cast, const_pointer_cast, dynamic_pointer_cast): Use
+ element_type instead of _Tp.
+ (reinterpret_pointer_cast): Define for C++17.
+ (weak_ptr::_Convertible): Replace with _Constructible.
+ (weak_ptr::_Constructible, weak_ptr::_Assignable): Forward checks
+ to base class.
+ (weak_ptr::weak_ptr, weak_ptr::operator=): Constrain templates
+ with _Constructible and _Assignable.
+ * include/bits/shared_ptr_base.h (__shared_ptr::_Convertible): Replace
+ with _Compatible.
+ (__shared_ptr::_SafeConv): New constraint for incoming raw pointers.
+ (__shared_ptr::_Compatible): New constraint for converting from
+ other types of shared_ptr and weak_ptr.
+ (__shared_ptr::_Assignable): Define in terms of _Compatible.
+ (__shared_ptr::_UniqCompatible, __shared_ptr::_UniqAssignable): New
+ constraints for converting from unique_ptr.
+ (__shared_ptr::__shared_ptr, __shared_ptr::operator=): Constrain
+ template with _SaveConf, _Compatible and _Assignable. Remove
+ __glibcxx_function_requires concept checks. Add static assertion for
+ deleter expression being well-formed.
+ (__shared_ptr::__shared_ptr(__shared_ptr<_Tp1>, _Tp*))
+ (__shared_ptr::operator*, __shared_ptr::operator->)
+ (__shared_ptr::get, __shared_ptr::_M_ptr): Use element_type instead
+ of _Tp.
+ (operator<): Likewise.
+ (operator>): Define in terms of operator<.
+ (static_pointer_cast, const_pointer_cast, dynamic_pointer_cast): Use
+ element_type instead of _Tp.
+ (reinterpret_pointer_cast): Define for C++17.
+ (weak_ptr::_Convertible): Replace with _Compatible.
+ (weak_ptr::_Compatible, weak_ptr::_Assignable): New constraints for
+ conversions from other types of weak_ptr and shared_ptr.
+ (__weak_ptr::__weak_ptr, __weak_ptr::operator=): Constrain templates
+ with _Constructible and _Assignable.
+ (__weak_ptr::_M_ptr): Use element_type instead of _Tp.
+ * testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc: Adjust
+ dg-error pattern.
+ * testsuite/20_util/shared_ptr/cons/auto_ptr.cc: Test conversions.
+ * testsuite/20_util/shared_ptr/cons/unique_ptr.cc: Likewise.
+ * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise.
+ * testsuite/20_util/shared_ptr/casts/reinterpret.cc: New test.
+
2016-10-20 Ville Voutilainen <ville.voutilainen@gmail.com>
Do the operator= SFINAE in the return type for optional,
{ __r.release(); }
template<typename _Tp, _Lock_policy _Lp>
- template<typename _Tp1>
+ template<typename _Tp1, typename>
inline
__shared_ptr<_Tp, _Lp>::__shared_ptr(std::auto_ptr<_Tp1>&& __r)
: _M_ptr(__r.get()), _M_refcount()
}
template<typename _Tp>
- template<typename _Tp1>
+ template<typename _Tp1, typename>
inline
shared_ptr<_Tp>::shared_ptr(std::auto_ptr<_Tp1>&& __r)
: __shared_ptr<_Tp>(std::move(__r)) { }
template<typename _Tp>
class shared_ptr : public __shared_ptr<_Tp>
{
- template<typename _Ptr>
- using _Convertible = typename
- enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
+ template<typename... _Args>
+ using _Constructible = typename enable_if<
+ is_constructible<__shared_ptr<_Tp>, _Args...>::value
+ >::type;
- template<typename _Ptr>
- using _Assignable = typename
- enable_if<is_convertible<_Ptr, _Tp*>::value, shared_ptr&>::type;
+ template<typename _Arg>
+ using _Assignable = typename enable_if<
+ is_assignable<__shared_ptr<_Tp>&, _Arg>::value, shared_ptr&
+ >::type;
public:
+ using element_type = typename __shared_ptr<_Tp>::element_type;
+
#if __cplusplus > 201402L
# define __cpp_lib_shared_ptr_weak_type 201606
using weak_type = weak_ptr<_Tp>;
* @brief Construct an empty %shared_ptr.
* @post use_count()==0 && get()==0
*/
- constexpr shared_ptr() noexcept
- : __shared_ptr<_Tp>() { }
+ constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { }
shared_ptr(const shared_ptr&) noexcept = default;
* @post use_count() == 1 && get() == __p
* @throw std::bad_alloc, in which case @c delete @a __p is called.
*/
- template<typename _Tp1>
- explicit shared_ptr(_Tp1* __p)
- : __shared_ptr<_Tp>(__p) { }
+ template<typename _Yp, typename = _Constructible<_Yp*>>
+ explicit
+ shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
/**
* @brief Construct a %shared_ptr that owns the pointer @a __p
*
* __shared_ptr will release __p by calling __d(__p)
*/
- template<typename _Tp1, typename _Deleter>
- shared_ptr(_Tp1* __p, _Deleter __d)
+ template<typename _Yp, typename _Deleter,
+ typename = _Constructible<_Yp*, _Deleter>>
+ shared_ptr(_Yp* __p, _Deleter __d)
: __shared_ptr<_Tp>(__p, __d) { }
/**
*
* __shared_ptr will release __p by calling __d(__p)
*/
- template<typename _Tp1, typename _Deleter, typename _Alloc>
- shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
+ template<typename _Yp, typename _Deleter, typename _Alloc,
+ typename = _Constructible<_Yp*, _Deleter, _Alloc>>
+ shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: __shared_ptr<_Tp>(__p, __d, std::move(__a)) { }
/**
* assert(pii.use_count() == 2);
* @endcode
*/
- template<typename _Tp1>
- shared_ptr(const shared_ptr<_Tp1>& __r, _Tp* __p) noexcept
+ template<typename _Yp>
+ shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) noexcept
: __shared_ptr<_Tp>(__r, __p) { }
/**
* @param __r A %shared_ptr.
* @post get() == __r.get() && use_count() == __r.use_count()
*/
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- shared_ptr(const shared_ptr<_Tp1>& __r) noexcept
+ template<typename _Yp,
+ typename = _Constructible<const shared_ptr<_Yp>&>>
+ shared_ptr(const shared_ptr<_Yp>& __r) noexcept
: __shared_ptr<_Tp>(__r) { }
/**
* @param __r A %shared_ptr rvalue.
* @post *this contains the old value of @a __r, @a __r is empty.
*/
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- shared_ptr(shared_ptr<_Tp1>&& __r) noexcept
+ template<typename _Yp, typename = _Constructible<shared_ptr<_Yp>>>
+ shared_ptr(shared_ptr<_Yp>&& __r) noexcept
: __shared_ptr<_Tp>(std::move(__r)) { }
/**
* @throw bad_weak_ptr when __r.expired(),
* in which case the constructor has no effect.
*/
- template<typename _Tp1>
- explicit shared_ptr(const weak_ptr<_Tp1>& __r)
+ template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
+ explicit shared_ptr(const weak_ptr<_Yp>& __r)
: __shared_ptr<_Tp>(__r) { }
#if _GLIBCXX_USE_DEPRECATED
- template<typename _Tp1>
- shared_ptr(std::auto_ptr<_Tp1>&& __r);
+ template<typename _Yp, typename = _Constructible<auto_ptr<_Yp>>>
+ shared_ptr(auto_ptr<_Yp>&& __r);
#endif
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2399. shared_ptr's constructor from unique_ptr should be constrained
- template<typename _Tp1, typename _Del, typename
- = _Convertible<typename unique_ptr<_Tp1, _Del>::pointer>>
- shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
+ template<typename _Yp, typename _Del,
+ typename = _Constructible<unique_ptr<_Yp, _Del>>>
+ shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: __shared_ptr<_Tp>(std::move(__r)) { }
/**
shared_ptr& operator=(const shared_ptr&) noexcept = default;
- template<typename _Tp1>
- _Assignable<_Tp1*>
- operator=(const shared_ptr<_Tp1>& __r) noexcept
+ template<typename _Yp>
+ _Assignable<const shared_ptr<_Yp>&>
+ operator=(const shared_ptr<_Yp>& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(__r);
return *this;
}
#if _GLIBCXX_USE_DEPRECATED
- template<typename _Tp1>
- shared_ptr&
- operator=(std::auto_ptr<_Tp1>&& __r)
+ template<typename _Yp>
+ _Assignable<auto_ptr<_Yp>>
+ operator=(auto_ptr<_Yp>&& __r)
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
return *this;
}
- template<class _Tp1>
- _Assignable<_Tp1*>
- operator=(shared_ptr<_Tp1>&& __r) noexcept
+ template<class _Yp>
+ _Assignable<shared_ptr<_Yp>>
+ operator=(shared_ptr<_Yp>&& __r) noexcept
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
}
- template<typename _Tp1, typename _Del>
- _Assignable<typename unique_ptr<_Tp1, _Del>::pointer>
- operator=(std::unique_ptr<_Tp1, _Del>&& __r)
+ template<typename _Yp, typename _Del>
+ _Assignable<unique_ptr<_Yp, _Del>>
+ operator=(unique_ptr<_Yp, _Del>&& __r)
{
this->__shared_ptr<_Tp>::operator=(std::move(__r));
return *this;
: __shared_ptr<_Tp>(__tag, __a, std::forward<_Args>(__args)...)
{ }
- template<typename _Tp1, typename _Alloc, typename... _Args>
- friend shared_ptr<_Tp1>
+ template<typename _Yp, typename _Alloc, typename... _Args>
+ friend shared_ptr<_Yp>
allocate_shared(const _Alloc& __a, _Args&&... __args);
// This constructor is non-standard, it is used by weak_ptr::lock().
};
// 20.7.2.2.7 shared_ptr comparisons
- template<typename _Tp1, typename _Tp2>
+ template<typename _Tp, typename _Up>
inline bool
- operator==(const shared_ptr<_Tp1>& __a,
- const shared_ptr<_Tp2>& __b) noexcept
+ operator==(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return __a.get() == __b.get(); }
template<typename _Tp>
operator==(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return !__a; }
- template<typename _Tp1, typename _Tp2>
+ template<typename _Tp, typename _Up>
inline bool
- operator!=(const shared_ptr<_Tp1>& __a,
- const shared_ptr<_Tp2>& __b) noexcept
+ operator!=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return __a.get() != __b.get(); }
template<typename _Tp>
operator!=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return (bool)__a; }
- template<typename _Tp1, typename _Tp2>
+ template<typename _Tp, typename _Up>
inline bool
- operator<(const shared_ptr<_Tp1>& __a,
- const shared_ptr<_Tp2>& __b) noexcept
+ operator<(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{
- typedef typename std::common_type<_Tp1*, _Tp2*>::type _CT;
- return std::less<_CT>()(__a.get(), __b.get());
+ using _Tp_elt = typename shared_ptr<_Tp>::element_type;
+ using _Up_elt = typename shared_ptr<_Up>::element_type;
+ using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
+ return less<_Vp>()(__a.get(), __b.get());
}
template<typename _Tp>
inline bool
operator<(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
- { return std::less<_Tp*>()(__a.get(), nullptr); }
+ {
+ using _Tp_elt = typename shared_ptr<_Tp>::element_type;
+ return less<_Tp_elt*>()(__a.get(), nullptr);
+ }
template<typename _Tp>
inline bool
operator<(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
- { return std::less<_Tp*>()(nullptr, __a.get()); }
+ {
+ using _Tp_elt = typename shared_ptr<_Tp>::element_type;
+ return less<_Tp_elt*>()(nullptr, __a.get());
+ }
- template<typename _Tp1, typename _Tp2>
+ template<typename _Tp, typename _Up>
inline bool
- operator<=(const shared_ptr<_Tp1>& __a,
- const shared_ptr<_Tp2>& __b) noexcept
+ operator<=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return !(__b < __a); }
template<typename _Tp>
operator<=(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
{ return !(__a < nullptr); }
- template<typename _Tp1, typename _Tp2>
+ template<typename _Tp, typename _Up>
inline bool
- operator>(const shared_ptr<_Tp1>& __a,
- const shared_ptr<_Tp2>& __b) noexcept
+ operator>(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return (__b < __a); }
template<typename _Tp>
inline bool
operator>(const shared_ptr<_Tp>& __a, nullptr_t) noexcept
- { return std::less<_Tp*>()(nullptr, __a.get()); }
+ { return nullptr < __a; }
template<typename _Tp>
inline bool
operator>(nullptr_t, const shared_ptr<_Tp>& __a) noexcept
- { return std::less<_Tp*>()(__a.get(), nullptr); }
+ { return __a < nullptr; }
- template<typename _Tp1, typename _Tp2>
+ template<typename _Tp, typename _Up>
inline bool
- operator>=(const shared_ptr<_Tp1>& __a,
- const shared_ptr<_Tp2>& __b) noexcept
+ operator>=(const shared_ptr<_Tp>& __a, const shared_ptr<_Up>& __b) noexcept
{ return !(__a < __b); }
template<typename _Tp>
{ __a.swap(__b); }
// 20.7.2.2.9 shared_ptr casts.
- template<typename _Tp, typename _Tp1>
+ template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
- static_pointer_cast(const shared_ptr<_Tp1>& __r) noexcept
- { return shared_ptr<_Tp>(__r, static_cast<_Tp*>(__r.get())); }
+ static_pointer_cast(const shared_ptr<_Up>& __r) noexcept
+ {
+ using _Sp = shared_ptr<_Tp>;
+ return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
+ }
- template<typename _Tp, typename _Tp1>
+ template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
- const_pointer_cast(const shared_ptr<_Tp1>& __r) noexcept
- { return shared_ptr<_Tp>(__r, const_cast<_Tp*>(__r.get())); }
+ const_pointer_cast(const shared_ptr<_Up>& __r) noexcept
+ {
+ using _Sp = shared_ptr<_Tp>;
+ return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
+ }
- template<typename _Tp, typename _Tp1>
+ template<typename _Tp, typename _Up>
inline shared_ptr<_Tp>
- dynamic_pointer_cast(const shared_ptr<_Tp1>& __r) noexcept
+ dynamic_pointer_cast(const shared_ptr<_Up>& __r) noexcept
{
- if (_Tp* __p = dynamic_cast<_Tp*>(__r.get()))
- return shared_ptr<_Tp>(__r, __p);
- return shared_ptr<_Tp>();
+ using _Sp = shared_ptr<_Tp>;
+ if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
+ return _Sp(__r, __p);
+ return _Sp();
}
+#if __cplusplus > 201402L
+ template<typename _Tp, typename _Up>
+ inline shared_ptr<_Tp>
+ reinterpret_pointer_cast(const shared_ptr<_Up>& __r) noexcept
+ {
+ using _Sp = shared_ptr<_Tp>;
+ return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
+ }
+#endif
/**
* @brief A smart pointer with weak semantics.
template<typename _Tp>
class weak_ptr : public __weak_ptr<_Tp>
{
- template<typename _Ptr>
- using _Convertible
- = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
+ template<typename _Arg>
+ using _Constructible = typename enable_if<
+ is_constructible<__weak_ptr<_Tp>, _Arg>::value
+ >::type;
+
+ template<typename _Arg>
+ using _Assignable = typename enable_if<
+ is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr&
+ >::type;
public:
constexpr weak_ptr() noexcept = default;
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- weak_ptr(const shared_ptr<_Tp1>& __r) noexcept
+ template<typename _Yp,
+ typename = _Constructible<const shared_ptr<_Yp>&>>
+ weak_ptr(const shared_ptr<_Yp>& __r) noexcept
: __weak_ptr<_Tp>(__r) { }
weak_ptr(const weak_ptr&) noexcept = default;
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- weak_ptr(const weak_ptr<_Tp1>& __r) noexcept
+ template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
+ weak_ptr(const weak_ptr<_Yp>& __r) noexcept
: __weak_ptr<_Tp>(__r) { }
weak_ptr(weak_ptr&&) noexcept = default;
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- weak_ptr(weak_ptr<_Tp1>&& __r) noexcept
+ template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>>
+ weak_ptr(weak_ptr<_Yp>&& __r) noexcept
: __weak_ptr<_Tp>(std::move(__r)) { }
weak_ptr&
operator=(const weak_ptr& __r) noexcept = default;
- template<typename _Tp1>
- weak_ptr&
- operator=(const weak_ptr<_Tp1>& __r) noexcept
+ template<typename _Yp>
+ _Assignable<const weak_ptr<_Yp>&>
+ operator=(const weak_ptr<_Yp>& __r) noexcept
{
this->__weak_ptr<_Tp>::operator=(__r);
return *this;
}
- template<typename _Tp1>
- weak_ptr&
- operator=(const shared_ptr<_Tp1>& __r) noexcept
+ template<typename _Yp>
+ _Assignable<const shared_ptr<_Yp>&>
+ operator=(const shared_ptr<_Yp>& __r) noexcept
{
this->__weak_ptr<_Tp>::operator=(__r);
return *this;
weak_ptr&
operator=(weak_ptr&& __r) noexcept = default;
- template<typename _Tp1>
- weak_ptr&
- operator=(weak_ptr<_Tp1>&& __r) noexcept
+ template<typename _Yp>
+ _Assignable<weak_ptr<_Yp>>
+ operator=(weak_ptr<_Yp>&& __r) noexcept
{
this->__weak_ptr<_Tp>::operator=(std::move(__r));
return *this;
_M_pi = nullptr;
}
+ // Helper traits for shared_ptr
+
+ template<typename _Yp_ptr, typename _Tp_ptr>
+ struct __sp_compatible_with
+ : false_type
+ { };
+
+ template<typename _Yp, typename _Tp>
+ struct __sp_compatible_with<_Yp*, _Tp*>
+ : is_convertible<_Yp*, _Tp*>::type
+ { };
+
template<typename _Tp, _Lock_policy _Lp>
class __shared_ptr
{
- template<typename _Ptr>
- using _Convertible
- = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
+ public:
+ using element_type = _Tp;
- template<typename _Ptr>
- using _Assignable = typename
- enable_if<is_convertible<_Ptr, _Tp*>::value, __shared_ptr&>::type;
+ private:
+ // Trait to check if shared_ptr<T> can be constructed from Y*.
+ template<typename _Tp1, typename _Yp>
+ using __sp_is_constructible = is_convertible<_Yp*, _Tp1*>;
+
+ // Constraint for taking ownership of a pointer of type _Yp*:
+ template<typename _Yp>
+ using _SafeConv
+ = typename enable_if<__sp_is_constructible<_Tp, _Yp>::value>::type;
+
+ // Constraint for construction from shared_ptr and weak_ptr:
+ template<typename _Yp, typename _Res = void>
+ using _Compatible = typename
+ enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
+
+ // Constraint for assignment from shared_ptr and weak_ptr:
+ template<typename _Yp>
+ using _Assignable = _Compatible<_Yp, __shared_ptr&>;
+
+ // Constraint for construction from unique_ptr:
+ template<typename _Yp, typename _Del, typename _Res = void,
+ typename _Ptr = typename unique_ptr<_Yp, _Del>::pointer>
+ using _UniqCompatible = typename enable_if<
+ is_convertible<_Ptr, element_type*>::value
+ , _Res>::type;
+
+ // Constraint for assignment from unique_ptr:
+ template<typename _Yp, typename _Del>
+ using _UniqAssignable = _UniqCompatible<_Yp, _Del, __shared_ptr&>;
public:
- typedef _Tp element_type;
#if __cplusplus > 201402L
using weak_type = __weak_ptr<_Tp, _Lp>;
: _M_ptr(0), _M_refcount()
{ }
- template<typename _Tp1>
- explicit __shared_ptr(_Tp1* __p)
- : _M_ptr(__p), _M_refcount(__p)
+ template<typename _Yp, typename = _SafeConv<_Yp>>
+ explicit
+ __shared_ptr(_Yp* __p)
+ : _M_ptr(__p), _M_refcount(__p)
{
- __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
- static_assert( !is_void<_Tp1>::value, "incomplete type" );
- static_assert( sizeof(_Tp1) > 0, "incomplete type" );
+ static_assert( !is_void<_Yp>::value, "incomplete type" );
+ static_assert( sizeof(_Yp) > 0, "incomplete type" );
_M_enable_shared_from_this_with(__p);
}
- template<typename _Tp1, typename _Deleter>
- __shared_ptr(_Tp1* __p, _Deleter __d)
+ template<typename _Yp, typename _Deleter, typename = _SafeConv<_Yp>>
+ __shared_ptr(_Yp* __p, _Deleter __d)
: _M_ptr(__p), _M_refcount(__p, __d)
{
- __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
- // TODO requires _Deleter CopyConstructible and __d(__p) well-formed
+ static_assert(__is_callable<_Deleter(_Yp*)>::value,
+ "deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p);
}
- template<typename _Tp1, typename _Deleter, typename _Alloc>
- __shared_ptr(_Tp1* __p, _Deleter __d, _Alloc __a)
+ template<typename _Yp, typename _Deleter, typename _Alloc,
+ typename = _SafeConv<_Yp>>
+ __shared_ptr(_Yp* __p, _Deleter __d, _Alloc __a)
: _M_ptr(__p), _M_refcount(__p, __d, std::move(__a))
{
- __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
- // TODO requires _Deleter CopyConstructible and __d(__p) well-formed
+ static_assert(__is_callable<_Deleter(_Yp*)>::value,
+ "deleter expression d(p) is well-formed");
_M_enable_shared_from_this_with(__p);
}
: _M_ptr(0), _M_refcount(__p, __d, std::move(__a))
{ }
- template<typename _Tp1>
- __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r, _Tp* __p) noexcept
+ template<typename _Yp>
+ __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r,
+ element_type* __p) noexcept
: _M_ptr(__p), _M_refcount(__r._M_refcount) // never throws
{ }
__shared_ptr& operator=(const __shared_ptr&) noexcept = default;
~__shared_ptr() = default;
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ __shared_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
{ }
__r._M_ptr = 0;
}
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- __shared_ptr(__shared_ptr<_Tp1, _Lp>&& __r) noexcept
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ __shared_ptr(__shared_ptr<_Yp, _Lp>&& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount()
{
_M_refcount._M_swap(__r._M_refcount);
__r._M_ptr = 0;
}
- template<typename _Tp1>
- explicit __shared_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ explicit __shared_ptr(const __weak_ptr<_Yp, _Lp>& __r)
: _M_refcount(__r._M_refcount) // may throw
{
- __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
-
// It is now safe to copy __r._M_ptr, as
// _M_refcount(__r._M_refcount) did not throw.
_M_ptr = __r._M_ptr;
}
// If an exception is thrown this constructor has no effect.
- template<typename _Tp1, typename _Del, typename
- = _Convertible<typename unique_ptr<_Tp1, _Del>::pointer>>
- __shared_ptr(std::unique_ptr<_Tp1, _Del>&& __r)
+ template<typename _Yp, typename _Del,
+ typename = _UniqCompatible<_Yp, _Del>>
+ __shared_ptr(unique_ptr<_Yp, _Del>&& __r)
: _M_ptr(__r.get()), _M_refcount()
{
- __glibcxx_function_requires(_ConvertibleConcept<_Tp1*, _Tp*>)
auto __raw = _S_raw_ptr(__r.get());
_M_refcount = __shared_count<_Lp>(std::move(__r));
_M_enable_shared_from_this_with(__raw);
#if _GLIBCXX_USE_DEPRECATED
// Postcondition: use_count() == 1 and __r.get() == 0
- template<typename _Tp1>
- __shared_ptr(std::auto_ptr<_Tp1>&& __r);
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ __shared_ptr(auto_ptr<_Yp>&& __r);
#endif
constexpr __shared_ptr(nullptr_t) noexcept : __shared_ptr() { }
- template<typename _Tp1>
- _Assignable<_Tp1*>
- operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
+ template<typename _Yp>
+ _Assignable<_Yp>
+ operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r._M_ptr;
_M_refcount = __r._M_refcount; // __shared_count::op= doesn't throw
}
#if _GLIBCXX_USE_DEPRECATED
- template<typename _Tp1>
- __shared_ptr&
- operator=(std::auto_ptr<_Tp1>&& __r)
+ template<typename _Yp>
+ _Assignable<_Yp>
+ operator=(auto_ptr<_Yp>&& __r)
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
return *this;
}
- template<class _Tp1>
- _Assignable<_Tp1*>
- operator=(__shared_ptr<_Tp1, _Lp>&& __r) noexcept
+ template<class _Yp>
+ _Assignable<_Yp>
+ operator=(__shared_ptr<_Yp, _Lp>&& __r) noexcept
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
}
- template<typename _Tp1, typename _Del>
- _Assignable<typename unique_ptr<_Tp1, _Del>::pointer>
- operator=(std::unique_ptr<_Tp1, _Del>&& __r)
+ template<typename _Yp, typename _Del>
+ _UniqAssignable<_Yp, _Del>
+ operator=(unique_ptr<_Yp, _Del>&& __r)
{
__shared_ptr(std::move(__r)).swap(*this);
return *this;
reset() noexcept
{ __shared_ptr().swap(*this); }
- template<typename _Tp1>
- _Convertible<_Tp1*>
- reset(_Tp1* __p) // _Tp1 must be complete.
+ template<typename _Yp>
+ _SafeConv<_Yp>
+ reset(_Yp* __p) // _Yp must be complete.
{
// Catch self-reset errors.
__glibcxx_assert(__p == 0 || __p != _M_ptr);
__shared_ptr(__p).swap(*this);
}
- template<typename _Tp1, typename _Deleter>
- _Convertible<_Tp1*>
- reset(_Tp1* __p, _Deleter __d)
+ template<typename _Yp, typename _Deleter>
+ _SafeConv<_Yp>
+ reset(_Yp* __p, _Deleter __d)
{ __shared_ptr(__p, __d).swap(*this); }
- template<typename _Tp1, typename _Deleter, typename _Alloc>
- _Convertible<_Tp1*>
- reset(_Tp1* __p, _Deleter __d, _Alloc __a)
+ template<typename _Yp, typename _Deleter, typename _Alloc>
+ _SafeConv<_Yp>
+ reset(_Yp* __p, _Deleter __d, _Alloc __a)
{ __shared_ptr(__p, __d, std::move(__a)).swap(*this); }
// Allow class instantiation when _Tp is [cv-qual] void.
- typename std::add_lvalue_reference<_Tp>::type
+ typename std::add_lvalue_reference<element_type>::type
operator*() const noexcept
{
__glibcxx_assert(_M_ptr != 0);
return *_M_ptr;
}
- _Tp*
+ element_type*
operator->() const noexcept
{
_GLIBCXX_DEBUG_PEDASSERT(_M_ptr != 0);
return _M_ptr;
}
- _Tp*
+ element_type*
get() const noexcept
{ return _M_ptr; }
template<typename _Del, typename _Tp1, _Lock_policy _Lp1>
friend _Del* get_deleter(const __shared_ptr<_Tp1, _Lp1>&) noexcept;
- _Tp* _M_ptr; // Contained pointer.
+ element_type* _M_ptr; // Contained pointer.
__shared_count<_Lp> _M_refcount; // Reference counter.
};
operator!=(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
{ return (bool)__a; }
- template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
+ template<typename _Tp, typename _Up, _Lock_policy _Lp>
inline bool
- operator<(const __shared_ptr<_Tp1, _Lp>& __a,
- const __shared_ptr<_Tp2, _Lp>& __b) noexcept
+ operator<(const __shared_ptr<_Tp, _Lp>& __a,
+ const __shared_ptr<_Up, _Lp>& __b) noexcept
{
- typedef typename std::common_type<_Tp1*, _Tp2*>::type _CT;
- return std::less<_CT>()(__a.get(), __b.get());
+ using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
+ using _Up_elt = typename __shared_ptr<_Up, _Lp>::element_type;
+ using _Vp = typename common_type<_Tp_elt*, _Up_elt*>::type;
+ return less<_Vp>()(__a.get(), __b.get());
}
template<typename _Tp, _Lock_policy _Lp>
inline bool
operator<(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
- { return std::less<_Tp*>()(__a.get(), nullptr); }
+ {
+ using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
+ return less<_Tp_elt*>()(__a.get(), nullptr);
+ }
template<typename _Tp, _Lock_policy _Lp>
inline bool
operator<(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
- { return std::less<_Tp*>()(nullptr, __a.get()); }
+ {
+ using _Tp_elt = typename __shared_ptr<_Tp, _Lp>::element_type;
+ return less<_Tp_elt*>()(nullptr, __a.get());
+ }
template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
template<typename _Tp, _Lock_policy _Lp>
inline bool
operator>(const __shared_ptr<_Tp, _Lp>& __a, nullptr_t) noexcept
- { return std::less<_Tp*>()(nullptr, __a.get()); }
+ { return nullptr < __a; }
template<typename _Tp, _Lock_policy _Lp>
inline bool
operator>(nullptr_t, const __shared_ptr<_Tp, _Lp>& __a) noexcept
- { return std::less<_Tp*>()(__a.get(), nullptr); }
+ { return __a < nullptr; }
template<typename _Tp1, typename _Tp2, _Lock_policy _Lp>
inline bool
template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
static_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
- { return __shared_ptr<_Tp, _Lp>(__r, static_cast<_Tp*>(__r.get())); }
+ {
+ using _Sp = __shared_ptr<_Tp, _Lp>;
+ return _Sp(__r, static_cast<typename _Sp::element_type*>(__r.get()));
+ }
// The seemingly equivalent code:
// shared_ptr<_Tp, _Lp>(const_cast<_Tp*>(__r.get()))
template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
inline __shared_ptr<_Tp, _Lp>
const_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
- { return __shared_ptr<_Tp, _Lp>(__r, const_cast<_Tp*>(__r.get())); }
+ {
+ using _Sp = __shared_ptr<_Tp, _Lp>;
+ return _Sp(__r, const_cast<typename _Sp::element_type*>(__r.get()));
+ }
// The seemingly equivalent code:
// shared_ptr<_Tp, _Lp>(dynamic_cast<_Tp*>(__r.get()))
inline __shared_ptr<_Tp, _Lp>
dynamic_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
{
- if (_Tp* __p = dynamic_cast<_Tp*>(__r.get()))
- return __shared_ptr<_Tp, _Lp>(__r, __p);
- return __shared_ptr<_Tp, _Lp>();
+ using _Sp = __shared_ptr<_Tp, _Lp>;
+ if (auto* __p = dynamic_cast<typename _Sp::element_type*>(__r.get()))
+ return _Sp(__r, __p);
+ return _Sp();
}
+#if __cplusplus > 201402L
+ template<typename _Tp, typename _Tp1, _Lock_policy _Lp>
+ inline __shared_ptr<_Tp, _Lp>
+ reinterpret_pointer_cast(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
+ {
+ using _Sp = __shared_ptr<_Tp, _Lp>;
+ return _Sp(__r, reinterpret_cast<typename _Sp::element_type*>(__r.get()));
+ }
+#endif
template<typename _Tp, _Lock_policy _Lp>
class __weak_ptr
{
- template<typename _Ptr>
- using _Convertible
- = typename enable_if<is_convertible<_Ptr, _Tp*>::value>::type;
+ template<typename _Yp, typename _Res = void>
+ using _Compatible = typename
+ enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
+
+ // Constraint for assignment from shared_ptr and weak_ptr:
+ template<typename _Yp>
+ using _Assignable = _Compatible<_Yp, __weak_ptr&>;
public:
- typedef _Tp element_type;
+ using element_type = _Tp;
constexpr __weak_ptr() noexcept
: _M_ptr(nullptr), _M_refcount()
//
// It is not possible to avoid spurious access violations since
// in multithreaded programs __r._M_ptr may be invalidated at any point.
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r) noexcept
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept
: _M_refcount(__r._M_refcount)
{ _M_ptr = __r.lock().get(); }
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- __weak_ptr(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
: _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
{ }
: _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
{ __r._M_ptr = nullptr; }
- template<typename _Tp1, typename = _Convertible<_Tp1*>>
- __weak_ptr(__weak_ptr<_Tp1, _Lp>&& __r) noexcept
+ template<typename _Yp, typename = _Compatible<_Yp>>
+ __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept
: _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount))
{ __r._M_ptr = nullptr; }
__weak_ptr&
operator=(const __weak_ptr& __r) noexcept = default;
- template<typename _Tp1>
- __weak_ptr&
- operator=(const __weak_ptr<_Tp1, _Lp>& __r) noexcept
+ template<typename _Yp>
+ _Assignable<_Yp>
+ operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r.lock().get();
_M_refcount = __r._M_refcount;
return *this;
}
- template<typename _Tp1>
- __weak_ptr&
- operator=(const __shared_ptr<_Tp1, _Lp>& __r) noexcept
+ template<typename _Yp>
+ _Assignable<_Yp>
+ operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
{
_M_ptr = __r._M_ptr;
_M_refcount = __r._M_refcount;
return *this;
}
- template<typename _Tp1>
- __weak_ptr&
- operator=(__weak_ptr<_Tp1, _Lp>&& __r) noexcept
+ template<typename _Yp>
+ _Assignable<_Yp>
+ operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept
{
_M_ptr = __r.lock().get();
_M_refcount = std::move(__r._M_refcount);
friend class __enable_shared_from_this<_Tp, _Lp>;
friend class enable_shared_from_this<_Tp>;
- _Tp* _M_ptr; // Contained pointer.
+ element_type* _M_ptr; // Contained pointer.
__weak_count<_Lp> _M_refcount; // Reference counter.
};
{
std::shared_ptr<A> a;
std::auto_ptr<B> b;
- a = std::move(b); // { dg-error "here" }
+ a = std::move(b); // { dg-error "no match" }
return 0;
}
--- /dev/null
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++1z } }
+
+// Copyright (C) 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 copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 20.11.2.2.9 shared_ptr casts [util.smartptr.shared.cast]
+
+#include <memory>
+#include <testsuite_tr1.h>
+
+struct MyP { virtual ~MyP() { }; };
+struct MyDP : MyP { };
+
+int main()
+{
+ using __gnu_test::check_ret_type;
+ using std::shared_ptr;
+ using std::reinterpret_pointer_cast;
+
+ shared_ptr<double> spd;
+ shared_ptr<const int> spci;
+ shared_ptr<MyP> spa;
+
+ check_ret_type<shared_ptr<void> >(reinterpret_pointer_cast<void>(spd));
+ check_ret_type<shared_ptr<const short> >(reinterpret_pointer_cast<const short>(spci));
+ check_ret_type<shared_ptr<MyDP> >(reinterpret_pointer_cast<MyDP>(spa));
+}
struct A { };
+int destroyed = 0;
+struct B : A { ~B() { ++destroyed; } };
+
// 20.6.6.2.1 shared_ptr constructors [util.smartptr.shared.const]
// Construction from auto_ptr
-int
+
+template<typename From, typename To>
+constexpr bool constructible()
+{
+ using namespace std;
+ return is_constructible<shared_ptr<To>, auto_ptr<From>>::value
+ && is_constructible<shared_ptr<const To>, auto_ptr<From>>::value
+ && is_constructible<shared_ptr<const To>, auto_ptr<const From>>::value;
+}
+
+static_assert( constructible< A, A >(), "A -> A compatible" );
+static_assert( constructible< B, A >(), "B -> A compatible" );
+static_assert( constructible< int, int >(), "int -> int compatible" );
+static_assert( !constructible< int, long >(), "int -> long not compatible" );
+
+void
test01()
{
std::auto_ptr<A> a(new A);
VERIFY( a.get() == 0 );
VERIFY( a2.get() != 0 );
VERIFY( a2.use_count() == 1 );
+}
- return 0;
+void
+test02()
+{
+ std::auto_ptr<B> b(new B);
+ std::shared_ptr<A> a(std::move(b));
+ VERIFY( b.get() == 0 );
+ VERIFY( a.get() != 0 );
+ VERIFY( a.use_count() == 1 );
+ a.reset();
+ VERIFY( destroyed == 1 );
}
int
main()
{
test01();
+ test02();
return 0;
}
struct A { };
+int destroyed = 0;
+struct B : A { ~B() { ++destroyed; } };
+
// 20.7.2.2.1 shared_ptr constructors [util.smartptr.shared.const]
// Construction from unique_ptr
-int
+
+template<typename From, typename To>
+constexpr bool constructible()
+{
+ using namespace std;
+ return is_constructible<shared_ptr<To>, unique_ptr<From>>::value
+ && is_constructible<shared_ptr<const To>, unique_ptr<From>>::value
+ && is_constructible<shared_ptr<const To>, unique_ptr<const From>>::value;
+}
+
+static_assert( constructible< A, A >(), "A -> A compatible" );
+static_assert( constructible< B, A >(), "B -> A compatible" );
+static_assert( constructible< int, int >(), "int -> int compatible" );
+static_assert( !constructible< int, long >(), "int -> long not compatible" );
+
+void
test01()
{
std::unique_ptr<A> up(new A);
VERIFY( up.get() == 0 );
VERIFY( sp.get() != 0 );
VERIFY( sp.use_count() == 1 );
+}
- return 0;
+void
+test02()
+{
+ std::unique_ptr<B> b(new B);
+ std::shared_ptr<A> a(std::move(b));
+ VERIFY( b.get() == 0 );
+ VERIFY( a.get() != 0 );
+ VERIFY( a.use_count() == 1 );
+ a.reset();
+ VERIFY( destroyed == 1 );
}
int
main()
{
test01();
+ test02();
return 0;
}
std::shared_ptr<void> p((void*)nullptr); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 0 }
}
+
+using std::shared_ptr;
+using std::is_constructible;
+static_assert(!is_constructible<shared_ptr<void>, const void*>::value, "");