This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.
Section: 20.2 [memory] Status: C++11 Submitter: BSI Opened: 2010-08-25 Last modified: 2016-01-28
One reason that the unique_ptr
constructor taking a nullptr_t
argument is not explicit
is to allow conversion of nullptr
to unique_ptr
in contexts like equality comparison. Unfortunately operator==
for unique_ptr
is a little more clever than that, deducing template parameters for both arguments. This means that nullptr
does not get deduced as unique_ptr
type, and there are no other comparison functions to match.
Add the following signatures to 20.2 [memory] p.1, <memory>
header synopsis:
template<typename T, typename D> bool operator==(const unique_ptr<T, D> & lhs, nullptr_t); template<typename T, typename D> bool operator==(nullptr_t, const unique_ptr<T, D> & rhs); template<typename T, typename D> bool operator!=(const unique_ptr<T, D> & lhs, nullptr_t); template<typename T, typename D> bool operator!=(nullptr_t, const unique_ptr<T, D> & rhs);
The same problem applies to shared_ptr
as well: In both cases there are no conversions considered because the comparison functions are templates. I agree with the direction of the proposed resolution, but I believe it would be very surprising and inconsistent, if given a smart pointer object p
, the expression p == nullptr
would be provided, but not p < nullptr
and the other relational operators. According to 7.6.9 [expr.rel] they are defined if null pointer values meet other pointer values, even though the result is unspecified for all except some trivial ones. But null pointer values are nothing special here: The Library already defines the relational operators for both unique_ptr
and shared_ptr
and the outcome of comparing non-null pointer values will be equally unspecified. If the idea of supporting nullptr_t
arguments for relational operators is not what the committee prefers, I suggest at least to consider to remove the existing relational operators for both unique_ptr
and shared_ptr
for consistency. But that would not be my preferred resolution of this issue.
shared_ptr
comparison functions for consistency.
Issue 1297(i) is remotely related. The following proposed resolution splits this bullet into sub-bullets A and B. Sub-bullet A would also solve 1297(i), but sub-bullet B would not.
The underlying idea behind this approach is the assumption that nullptr corresponds to the least ordinal pointer value. But this assertion does not hold for all supported architectures, therefore this approach was not followed because it would lead to the inconsistency, that the following assertion could fire:
The current issue state is not acceptable, because the Batavia meeting did not give advice whether choice A or B of bullet 3 should be applied. Option B will now be removed and if this resolution is accepted, issue 1297(i) should be declared as resolved by 1401(i). This update also resyncs the wording with N3242.
Wording changes are against N3242.
<memory>
synopsis as indicated. noexcept
specifications are only added, where the guarantee exists, that the function shall no throw an exception (as replacement of "Throws: Nothing". Note that the noexcept
additions to the shared_ptr
comparisons are editorial, because they are already part of the accepted paper n3195:
namespace std { […] // [unique.ptr] Class unique_ptr: template <class T> class default_delete; template <class T> class default_delete<T[]>; template <class T, class D = default_delete<T>> class unique_ptr; template <class T, class D> class unique_ptr<T[], D>; template <class T1, class D1, class T2, class D2> bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x); // [util.smartptr.weakptr], Class bad_weak_ptr: class bad_weak_ptr; // [util.smartptr.shared], Class template shared_ptr: template<class T> class shared_ptr; // [util.smartptr.shared.cmp], shared_ptr comparisons: template<class T, class U> bool operator==(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; template<class T, class U> bool operator!=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; template<class T, class U> bool operator<(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; template<class T, class U> bool operator>(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; template<class T, class U> bool operator<=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; template<class T, class U> bool operator>=(shared_ptr<T> const& a, shared_ptr<U> const& b) noexcept; template<class T> bool operator==(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator==(nullptr_t, shared_ptr<T> const& a) noexcept; template<class T> bool operator!=(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator!=(nullptr_t, shared_ptr<T> const& a) noexcept; template<class T> bool operator<(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator<(nullptr_t, shared_ptr<T> const& a) noexcept; template>class T> bool operator>(shared_ptr<T> const& a, nullptr_t) noexcept; template>class T> bool operator>(nullptr_t, shared_ptr<T> const& a) noexcept; template<class T> bool operator<=(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator<=(nullptr_t, shared_ptr<T> const& a) noexcept; template>class T> bool operator>=(shared_ptr<T> const& a, nullptr_t) noexcept; template>class T> bool operator>=(nullptr_t, shared_ptr<T> const& a) noexcept; […] }
namespace std { […] template <class T1, class D1, class T2, class D2> bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x); }
Change 20.3.1.6 [unique.ptr.special] p. 4-7 as indicated and add a series of prototype descriptions:
template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);? Requires: Let
CT
becommon_type<unique_ptr<T1, D1>::pointer, unique_ptr<T2, D2>::pointer>::type
. Then the specializationless<CT>
shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.4 Returns:
less<CT>()(x.get(), y.get()) x.get() < y.get()
.? Remarks: If
unique_ptr<T1, D1>::pointer
is not implicitly convertible toCT
orunique_ptr<T2, D2>::pointer
is not implicitly convertible toCT
, the program is ill-formed.template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);5 Returns:
!(y < x) x.get() <= y.get()
.template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);6 Returns:
(y < x) x.get() > y.get()
.template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);7 Returns:
!(x < y) x.get() >= y.get()
.
template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept;? Returns:
!x
.
template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept;? Returns:
(bool) x
.
template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x);? Requires: The specialization
less<unique_ptr<T, D>::pointer>
shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.? Returns:
less<unique_ptr<T, D>::pointer>()(x.get(), nullptr)
.
template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t);? Requires: The specialization
less<unique_ptr<T, D>::pointer>
shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.? Returns:
less<unique_ptr<T, D>::pointer>()(nullptr, x.get())
.
template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x);? Returns:
!(nullptr < x)
.
template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t);? Returns:
!(x < nullptr)
.
Change 20.3.2.2 [util.smartptr.shared] p. 1, class template shared_ptr
synopsis as indicated. For consistency reasons the remaining normal relation operators are added as well:
namespace std { […] // [util.smartptr.shared.cmp], shared_ptr comparisons: template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T> bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator==(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator!=(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator<(nullptr_t, const shared_ptr<T>& a) noexcept; template>class T> bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept; template>class T> bool operator>(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator<=(nullptr_t, const shared_ptr<T>& a) noexcept; template>class T> bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept; template>class T> bool operator>=(nullptr_t, const shared_ptr<T>& a) noexcept; […] }
template<class T> bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator==(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns:
!a
.
template<class T> bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator!=(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns:
(bool) a
.
template<class T> bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator>(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns:
less<T*>()(a.get(), nullptr)
.
template<class T> bool operator<(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept;? Returns:
less<T*>()(nullptr, a.get())
.
template<class T> bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator>=(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns:
!(nullptr < a)
.
template<class T> bool operator<=(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept;? Returns:
!(a < nullptr)
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4