|Project||Programming Language C++, Library Working Group|
|Reply-to||Jonathan Wakely <firstname.lastname@example.org>|
The class template
std::owner_less is inconvenient to use for anything but
the simplest cases:
shared_ptr<int> sp1; shared_ptr<void> sp2; shared_ptr<long> sp3; weak_ptr<int> wp1; owner_less<shared_ptr<int>> cmp; cmp(sp1, sp2); // error, doesn't compile cmp(sp1, wp1); cmp(sp1, sp3); // error, doesn't compile cmp(wp1, sp1); cmp(wp1, wp1); // error, doesn't compile
The first error in the example in the introduction can be avoided by using
owner_less<shared_ptr<void>> but the initial attempt to do so still fails
sp1 can be converted to both
owner_less<shared_ptr<void>> cmpv; cmpv(sp1, sp2); // error, ambiguous conversion
To make it compile it's necessary to explicitly convert the
to the right argument type:
owner_less<shared_ptr<void>> cmpv; cmpv(shared_ptr<void>(sp1), sp2);
Not only is this more verbose and less clear, but the conversion creates a temporary, incrementing and decrementing the reference count.
weak_ptr::owner_before are function templates
that support mixed comparisons between
owner_less only supports comparing
Mixing pointers to different types either causes implicit conversions
(and reference-count updates) or just fails to compile.
This is an unnecessary restriction, because the
constructor means that objects which share ownership can store completely
unrelated types of pointer.
Even if we don't care about mixing different types,
owner_less::operator() overloads only support three out of four
combinations of argument types,
and the Adaptable Binary Function typedefs
only describe the argument types for one of those three overloads.
The proposed addition removes the typedefs, as they are unnecessary since C++11, and allows the example in the introduction to handle all the comparisons without creating any temporaries:
owner_less<> cmp; cmp(sp1, sp2); // no temporary created cmp(sp1, wp1); cmp(sp1, sp3); // ok cmp(wp1, sp1); cmp(wp1, wp1); // ok
The proposed addition is directly inspired by N3421 and so is not novel.
There is no need to constrain the proposed member function templates,
owner_before is unconstrained.
The member function templates simply return
bool rather than using
to detect the result of
x.owner_before(y). Although this means that in
N3421 terms the proposed specialization is not
completely "transparent" there is no need to use
is always the right return type.
By defining the nested
is_transparent typedef the following is supported:
set<shared_ptr<X>, owner_less<>> s; shared_ptr<void> key = get_key(); auto iter = s.find(key);
It might makes sense to alter the existing
owner_less<weak_ptr<T>> partial specializations to add a fourth overload
that takes two
weak_ptrs or two
shared_ptrs respectively, and also to
remove the nested typedefs. The fourth overload seems unnecessary if this
proposal is accepted, because it would still be simpler to use the new
owner_less<void> specialization. Removing the typedefs is a potentially
breaking change so is left for another proposal to do later if that change
This is a pure library extension. In C++ today
owner_less<void> is an
incomplete type, so defining it should not cause problems for any correct
In [util.smartptr.ownerless] p1 add a default template argument of type
template<class T> struct owner_less;
And after the two partial specializations add:
The implementation is trivial and has been tested in the GNU libstdc++ library.
Thanks to Marshal Clow for comments on the proposal.