Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
175 views
in Technique[技术] by (71.8m points)

c++ - How to concisely express the C++20 concept of range containing T-typed values?

I want to write a function template that accepts ranges of MyType-typed values, so I wrote

void f(const std::ranges::range auto& my_range) { /* ... */ }

Unfortunately this does not constrain the type of the values contained in the range. I could use a requires clause before the function body block but I want something reusable and not specific to this function.

Naturally I wrote

template <class T, class V>
concept range_of = std::ranges::range<T> && std::is_same_v<V, std::ranges::range_value_t<T>>;

void f(const range_of<MyType> auto& my_range) { /* ... */ }

but I'm very surprised that this is not supported out-of-the-box by the standard library given how natural it seems. This also applies to std::ranges::view for which I could write a similar view_of concept.

Is my definition of range_of incomplete or wrong? Or is there a good reason this isn't offered by the standard library?

question from:https://stackoverflow.com/questions/65894358/how-to-concisely-express-the-c20-concept-of-range-containing-t-typed-values

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem here is: what is the actual constraint that you want?

Do you want to:

  • constrain on the range's value type being specifically T?
  • constrain on the range's value type being convertible to T?
  • constrain on the range's value type satisfying some other concept, C?
  • any of the above but instead about the range's reference type?

Different contexts call for different versions of this. Your range_of concept is a perfectly fine implementation of the first one of these (could use std::same_as instead of std::is_same_v but doesn't super matter). But what happens when you want something else? The specific choice of constraint is going to depend very much on what it is you want to do.

So the direct answer is: there's no range_of concept because there's really no one true answer of what that concept should do.


A different answer would be that this isn't even what would be useful. What would be useful would be a direct way to pull out the associated types of a given range to make it easy to add further constraints on them.

For instance, if we take Rust, we can define a function that takes an arbitrary iterator:

fn foo<I: Iterator>(it: I) { ... }

That's sort of akin to just void f(range auto). It's a constraint, but not a very useful one. But Iterator, in Rust, has an associated type: its Item. So if you wanted an Iterator over a specific type, that's:

fn foo<I: Iterator<Item=i32>>(it: I) { ... }

If you wanted an Iterator whose type satisfies some other constraint:

fn foo<T: Debug, I: Iterator<Item=T>>(it: I) { ... }

And it's really this ability - to pull out associated types and constrain on them directly - that we really lack.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...