Section: 26.8 [alg.sorting] Status: C++20 Submitter: Jonathan Wakely Opened: 2017-11-08 Last modified: 2021-02-25
Priority: 2
View all other issues in [alg.sorting].
View all issues with C++20 status.
Discussion:
This doesn't compile with any major implementation:
int i[1] = { };
std::stable_sort(i, i, [](int& x, int& y) { return x < y; });
The problem is that the Compare expects non-const references. We say "It is assumed that
comp will not apply any non-constant function through the dereferenced iterator" But that
isn't sufficient to forbid the example.
Compare requirements use
comp(as_const(x), as_const(x)) but that would get very verbose to add to every expression
using comp.
[2017-11 Albuquerque Wednesday night issues processing]
Priority set to 2; Jonathan to improve the statement of the problem.
[2018-02 David Jones provided this truly awful example:]
#include <algorithm>
#include <iostream>
#include <vector>
struct Base {
Base(int value) : v(value) {}
friend bool operator<(const Base& l, const Base& r) { return l.v < r.v; }
int v;
};
struct Derived : public Base {
using Base::Base;
bool operator<(const Derived& o) /* no const here */ { return v > o.v; }
};
int main(void) {
std::vector<Base> b = {{1}, {5}, {0}, {3}};
std::vector<Derived> d = {{0}, {1}, {3}, {5}};
std::cout << std::lower_bound(d.begin(), d.end(), 4)->v << std::endl;
std::sort(b.begin(), b.end());
for (const auto &x : b) std::cout << x.v << " ";
std::cout << std::endl;
std::sort(d.begin(), d.end());
for (const auto &x : d) std::cout << x.v << " ";
std::cout << std::endl;
}
libc++:
=====
$ bin/clang++ -std=c++11 -stdlib=libc++ tmp/ex.cc && ./a.out
5
0 1 3 5
0 1 3 5
=====
libstdc++:
=====
$ bin/clang++ -std=c++11 -stdlib=libstdc++ tmp/ex.cc && ./a.out
0
0 1 3 5
5 3 1 0
=====
[2018-08 Batavia Monday issue discussion]
Tim to provide wording; status to 'Open'
[ 2018-08-20, Tim adds P/R based on Batavia discussion.]
Similar to the Ranges TS design, the P/R below requires Predicate,
BinaryPredicate, and Compare to accept all mixes of
const and non-const arguments.
[2018-08-23 Batavia Issues processing]
Status to Tentatively Ready after minor wording nit (corrected in place)
[2018-11, Adopted in San Diego]
Proposed resolution:
This wording is relative to N4762.
Edit 26.2 [algorithms.requirements] p6-7 as indicated:
-6- The
-7- ThePredicateparameter is used whenever an algorithm expects a function object (22.10 [function.objects]) that, when applied to the result of dereferencing the corresponding iterator, returns a value testable astrue. In other words, if an algorithm takesPredicate predas its argument andfirstas its iterator argument with value typeT, it should work correctly in the constructpred(*first)contextually converted tobool(7.3 [conv]). The function objectpredshall not apply any non-constant function through the dereferenced iterator. Given a glvalueuof type (possiblyconst)Tthat designates the same object as*first,pred(u)shall be a valid expression that is equal topred(*first).BinaryPredicateparameter is used whenever an algorithm expects a function object that when applied to the result of dereferencing two corresponding iterators or to dereferencing an iterator and typeTwhenTis part of the signature returns a value testable astrue. In other words, if an algorithm takesBinaryPredicate binary_predas its argument andfirst1andfirst2as its iterator arguments with respective value typesT1andT2, it should work correctly in the constructbinary_pred(*first1, *first2)contextually converted tobool(7.3 [conv]). Unless otherwise specified,BinaryPredicatealways takes the first iterator'svalue_typeas its first argument, that is, in those cases whenT valueis part of the signature, it should work correctly in the constructbinary_pred(*first1, value)contextually converted tobool(7.3 [conv]).binary_predshall not apply any non-constant function through the dereferenced iterators. Given a glvalueuof type (possiblyconst)T1that designates the same object as*first1, and a glvaluevof type (possiblyconst)T2that designates the same object as*first2,binary_pred(u, *first2),binary_pred(*first1, v), andbinary_pred(u, v)shall each be a valid expression that is equal tobinary_pred(*first1, *first2), andbinary_pred(u, value)shall be a valid expression that is equal tobinary_pred(*first1, value).
Edit 26.8 [alg.sorting] p2 as indicated:
Compareis a function object type (22.10 [function.objects]) that meets the requirements for a template parameter namedBinaryPredicate(26.2 [algorithms.requirements]). The return value of the function call operation applied to an object of typeCompare, when contextually converted tobool(7.3 [conv]), yieldstrueif the first argument of the call is less than the second, andfalseotherwise.Compare compis used throughout for algorithms assuming an ordering relation.It is assumed thatcompwill not apply any non-constant function through the dereferenced iterator.