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.
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_ptrshall 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_ptrs 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()), whereVis the composite pointer type (7.6.9 [expr.rel]).4 Throws: nothing.
5 For templatesgreater,less,greater_equal, andless_equal, the partial specializations forshared_ptrshall 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_ptrobjects 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_ptrshall 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_ptrobjects 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()), whereVis 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_ptrshall 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_ptrobjects to be used as keys in associative containers. — end note]