std::less<std::shared_ptr<T>>
is underspecifiedSection: 20.3.2.2.8 [util.smartptr.shared.cmp] Status: C++11 Submitter: Jonathan Wakely Opened: 2009-11-10 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [util.smartptr.shared.cmp].
View all issues with C++11 status.
Discussion:
20.3.2.2.8 [util.smartptr.shared.cmp]/5 says:
For templates
greater
,less
,greater_equal
, andless_equal
, the partial specializations forshared_ptr
shall yield a total order, even if the built-in operators<
,>
,<=
, and>=
do not. Moreover,less<shared_ptr<T> >::operator()(a, b)
shall returnstd::less<T*>::operator()(a.get(), b.get())
.
This is necessary in order to use shared_ptr
as the key in associate
containers because
n2637
changed operator<
on shared_ptr
s to be
defined in terms of operator<
on the stored pointers (a mistake IMHO
but too late now.) By 7.6.9 [expr.rel]/2 the result of comparing builtin
pointers is unspecified except in special cases which generally do not
apply to shared_ptr
.
Earlier versions of the WP (n2798, n2857) had the following note on that paragraph:
[Editor's note: It's not clear to me whether the first sentence is a requirement or a note. The second sentence seems to be a requirement, but it doesn't really belong here, under
operator<
.]
I agree completely - if partial specializations are needed they should be properly specified.
20.3.2.2.8 [util.smartptr.shared.cmp]/6 has a note saying the comparison operator
allows shared_ptr
objects to be used as keys in associative
containers, which is misleading because something else like a
std::less
partial specialization is needed. If it is not correct that
note should be removed.
20.3.2.2.8 [util.smartptr.shared.cmp]/3 refers to 'x
' and
'y
' but the prototype has parameters 'a
' and
'b
' - that needs to be fixed even if the rest of the issue is
NAD.
I see two ways to fix this, I prefer the first because it removes the
need for any partial specializations and also fixes operator>
and
other comparisons when defined in terms of operator<
.
Replace 20.3.2.2.8 [util.smartptr.shared.cmp]/3 with the following and remove p5:
template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b);3 Returns:
x.get() < y.get()
.std::less<V>()(a.get(), b.get())
, whereV
is the composite pointer type (7.6.9 [expr.rel]).4 Throws: nothing.
5 For templatesgreater
,less
,greater_equal
, andless_equal
, the partial specializations forshared_ptr
shall yield a total order, even if the built-in operators<
,>
,<=
, and>=
do not. Moreover,less<shared_ptr<T> >::operator()(a, b)
shall returnstd::less<T*>::operator()(a.get(), b.get())
.6 [Note: Defining a comparison operator allows
shared_ptr
objects to be used as keys in associative containers. — end note]
Add to 20.3.2.2 [util.smartptr.shared]/1 (after the shared_ptr
comparisons)
template<class T> struct greater<shared_ptr<T>>; template<class T> struct less<shared_ptr<T>>; template<class T> struct greater_equal<shared_ptr<T>>; template<class T> struct less_equal<shared_ptr<T>>;
Remove 20.3.2.2.8 [util.smartptr.shared.cmp]/5 and /6 and replace with:
template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b);3 Returns:
.
xa.get() <yb.get()4 Throws: nothing.
5 For templatesgreater
,less
,greater_equal
, andless_equal
, the partial specializations forshared_ptr
shall yield a total order, even if the built-in operators<
,>
,<=
, and>=
do not. Moreover,less<shared_ptr<T> >::operator()(a, b)
shall returnstd::less<T*>::operator()(a.get(), b.get())
.
6 [Note: Defining a comparison operator allowsshared_ptr
objects to be used as keys in associative containers. — end note]template<class T> struct greater<shared_ptr<T>> : binary_function<shared_ptr<T>, shared_ptr<T>, bool> { bool operator()(const shared_ptr<T>& a, const shared_ptr<T>& b) const; };
operator()
returnsgreater<T*>()(a.get(), b.get())
.template<class T> struct less<shared_ptr<T>> : binary_function<shared_ptr<T>, shared_ptr<T>, bool> { bool operator()(const shared_ptr<T>& a, const shared_ptr<T>& b) const; };
operator()
returnsless<T*>()(a.get(), b.get())
.template<class T> struct greater_equal<shared_ptr<T>> : binary_function<shared_ptr<T>, shared_ptr<T>, bool> { bool operator()(const shared_ptr<T>& a, const shared_ptr<T>& b) const; };
operator()
returnsgreater_equal<T*>()(a.get(), b.get())
.template<class T> struct less_equal<shared_ptr<T>> : binary_function<shared_ptr<T>, shared_ptr<T>, bool> { bool operator()(const shared_ptr<T>& a, const shared_ptr<T>& b) const; };
operator()
returnsless_equal<T*>()(a.get(), b.get())
.
[ 2009-11-18: Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]
Proposed resolution:
Replace 20.3.2.2.8 [util.smartptr.shared.cmp]/3 with the following and remove p5:
template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b);3 Returns:
x.get() < y.get()
.less<V>()(a.get(), b.get())
, whereV
is the composite pointer type (7.6.9 [expr.rel]) ofT*
andU*
.4 Throws: nothing.
5 For templatesgreater
,less
,greater_equal
, andless_equal
, the partial specializations forshared_ptr
shall yield a total order, even if the built-in operators<
,>
,<=
, and>=
do not. Moreover,less<shared_ptr<T> >::operator()(a, b)
shall returnstd::less<T*>::operator()(a.get(), b.get())
.6 [Note: Defining a comparison operator allows
shared_ptr
objects to be used as keys in associative containers. — end note]