C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::is_heap could take ForwardIterator, not RandomAccessIterator

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Wed, 29 Apr 2026 08:47:03 -0400
On Wed, Apr 29, 2026 at 4:51 AM Marcin Jaczewski <
marcinjaczewski86_at_[hidden]> wrote:

> śr., 29 kwi 2026 o 03:23 Arthur O'Dwyer via Std-Proposals <
> std-proposals_at_[hidden]> napisał(a):
> >
> > Has anyone previously brought up that `std::is_heap` is currently
> specified to take random-access iterators, but in fact (AFAICT) can easily
> be implemented to use only forward-iterator operations?
>
> But any other operation on this heap needs random-access, right?
> If this is true then the forward version will not be very useful as
> any other operation will be not available until you
> convert to some random access container.
>

That's right (or at least, I'm not considering/proposing to weaken the
requirements on any other algorithm with "heap" in its name).
Where this came up for me in real life was in a libc++ test, where we have
essentially

template <class Adaptor>

void test_push_range(bool is_result_heapified) {

  ~~~~

    Adaptor adaptor(test_case.initial.begin(), test_case.initial.end());

    ~~~~

    auto& c = ~~~~.get_container();


    if (is_result_heapified) {

      assert(std::ranges::is_heap(c));

      return std::ranges::is_permutation(c, test_case.expected);

    } else {

      return std::ranges::equal(c, test_case.expected);
    }

This template is used in the test suite for `std::queue` and in the test
suite for `std::priority_queue`. (In the former with
is_result_heapified=false; in the latter with is_result_heapified=true.)
By `std::queue` naturally I mean `std::queue<T, std::deque<T>>` — that's
the default underlying container for `queue`.
This is fine, today, because `deque` is a random-access container.
But suppose I want to extend the tests to also cover `Adaptor =
std::queue<T, std::list<T>>`. Then this template breaks; and it happens
that the *solitary* reason is `std::ranges::is_heap(c)` doesn't compile
anymore.

Now, obviously the constraint on is_heap isn't the *original* sin here.
Probably `test_push_range` ought to pass `is_result_heapified` as a
template parameter instead of a function parameter, and then use `if
constexpr` instead of `if` for that conditional. That would fix things, now
that we know there's a problem. But aesthetically I'm displeased that there
*was* any problem! There doesn't seem to be any good reason the code didn't
Just Work as originally written! It seems like perfectly reasonable
STL-style generic code to me.
Which does make me wonder if I'm missing something subtle. IIUC your
suggestion is that is_heap was originally overconstrained simply for
aesthetic reasons — to match push_heap and pop_heap — and I agree that's
plausible, but could there be some technical reason I haven't spotted yet?

Cheers,
Arthur

Received on 2026-04-29 12:47:17