Range concept for a specific type

1.9k views Asked by At

Is there an already defined concept for specifying a range of a specific type, in C++20 or in the ranges-TS?

Something like:

template < class T, class InnerType >
concept RangeOf =
  requires(T&& t) {
    requires std::same_as<
           std::remove_cvref_t<decltype(*std::ranges::begin(t))>,
           InnerType
         >;
    std::ranges::end(t);
  };

To allow, for example:

void print(const RangeOf<char> auto& char_seq) { /* ... */ }
1

There are 1 answers

5
Barry On BEST ANSWER

No there isn't.

The way to spell that particular concept would be:

template <typename R, typename V>
concept RangeOf = range<R> && same_as<range_value_t<R>, V>;

But then it turns out there's a bunch of very closely related things you might want to check as well. You might actually want to look at the reference type rather than the value_type. Perhaps that's:

template <typename R, typename V>
concept RangeOf = range<R> && same_as<range_reference_t<R>, V>;

The reason is: do you consider vector<char>& to be a range of char or a range of char&? Arguably, it's more like the latter, and it's the latter that drives a lot more usage. But it's not that the former is wrong; it's useful too, just in a different way.

Then you have to talk about whether you want same_as or convertible_to. There are some algorithms in which you would want to restrict to the former, and some in which the latter is good enough.

This issue of same_as vs convertible_to, to me, is one of the motivating reasons for wanting concept template parameters, so that:

template <typename R, template <typename> concept C>
concept RangeOf = range<R> && C<range_value_t<R>>;

So that I can easily write RangeOf<same_as<char>> or RangeOf<convertible_to<char>>, depending on what I actually want. However, this brings up other parsing issues too (if RangeOf takes a unary concept, how do you make same_as<char> - which is not a unary concept but rather a partially applied concept that is not valid in all contexts - work?) so it's unclear how to really make this work. There's currently a proposal for this, but it would not actually handle this use-case especially well (largely because it's not actually clear how to handle this use-case especially well).


All of which is to say, it's hard to know what actual thing we would want for RangeOf, which is why no such thing exists. But each specific thing that would be useful is very easy to write, so the lack of such a thing isn't a especially large burden on the user.