You have argued against your own conclusion, as evidenced here:
template <typename Container>
auto transform(Container&& container, auto&&... args)
requires ( requires {container.begin(); container.end(); }) {
So... what is this? It's a function which takes a template parameter that satisfies a constraint. Let's ignore that this constraint require member begin/end
instead of the more reasonable std::ranges::begin/end
requirements.
How many functions are you going to apply this requirement to? Probably lots. Every algorithm is going to have a version that has this requirement on it. So that's starting to look less like a one-off requirement and more like something that should be a named concept
.
Especially since that concept should probably specify what kind of iterator the algorithm requires. You don't just need member begin/end
; you need them to return an input_or_output_iterator
and a sentinel_for
that iterator:
requires ( requires(Container c)
{
{c.begin()} -> input_or_output_iterator;
{c.end()} -> sentinel_for<decltype(c.begin())>;
})
Do you really want to type this every time you ask for a "container"? Of course not; that's what named concepts are for.
So what is that concept? It's a thing over which you can iterate, a sequence of values that is accessible through a particular iterator interface.
And the name of that concept should probably be chosen so as not to imply ownership of the sequence of elements. The transform
algorithm doesn't care if what it is given owns the sequence or not. So "container" is absolutely the wrong name.
So let's call this concept a rangevalue-sequence. Value-sequences can be iterated over through an iterator/sentinel interface. And you'll probably need to have different categories of value-sequences. Input sequences, forward sequences, contiguous sequences, etc. You maybe want to detect whether the sequence can compute a size in constant time, or whether the sequence is bounded or borrowed from its owner.
And wouldn't it be neat if you could write operators that create views of these value-sequences?
A range by any other name smells just as sweet. Once you start down the dark path of pairing iterators with sentinels, forever will it dominate your destiny.
Ranges are a natural concept when dealing with iterators. And everything built off of the range concepts is an outgrowth of that.