Difference between revisions of "cpp/ranges/range"
From cppreference.com
(mention how to make a class satisfy this concept) |
m (→Example: {{source}} => {{example}} to enable online experiments.) |
||
(3 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{cpp/ranges/title|range}} | {{cpp/ranges/title|range}} | ||
{{cpp/ranges/navbar}} | {{cpp/ranges/navbar}} | ||
− | + | {{ddcl|header=ranges|since=c++20|1= | |
− | {{ | + | |
− | + | ||
− | + | ||
template< class T > | template< class T > | ||
concept range = requires( T& t ) { | concept range = requires( T& t ) { | ||
− | + | ranges::begin(t); // equality-preserving for forward iterators | |
− | + | ranges::end (t); | |
}; | }; | ||
}} | }} | ||
− | |||
The {{tt|range}} concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range. | The {{tt|range}} concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range. | ||
===Semantic requirements=== | ===Semantic requirements=== | ||
− | Given an expression {{c|E}} such that {{c|decltype((E))}} is {{ | + | Given an expression {{c|E}} such that {{c/core|decltype((E))}} is {{tt|T}}, {{tt|T}} models {{tt|range}} only if |
− | * | + | * {{range|ranges::begin(E)|ranges::end(E)}} denotes a [[cpp/iterator#Ranges|range]], and |
* both {{c|ranges::begin(E)}} and {{c|ranges::end(E)}} are amortized constant time and do not alter the value of {{c|E}} in a manner observable to [[cpp/concepts#Equality preservation|equality-preserving]] expressions, and | * both {{c|ranges::begin(E)}} and {{c|ranges::end(E)}} are amortized constant time and do not alter the value of {{c|E}} in a manner observable to [[cpp/concepts#Equality preservation|equality-preserving]] expressions, and | ||
* if the type of {{c|ranges::begin(E)}} models {{lconcept|forward_iterator}}, {{c|ranges::begin(E)}} is [[cpp/concepts#Equality preservation|equality-preserving]] (in other words, forward iterators support multi-pass algorithms). | * if the type of {{c|ranges::begin(E)}} models {{lconcept|forward_iterator}}, {{c|ranges::begin(E)}} is [[cpp/concepts#Equality preservation|equality-preserving]] (in other words, forward iterators support multi-pass algorithms). | ||
− | |||
===Notes=== | ===Notes=== | ||
Line 33: | Line 28: | ||
{{example | {{example | ||
|code= | |code= | ||
− | |||
#include <ranges> | #include <ranges> | ||
− | + | ||
− | + | // A minimum range | |
− | + | struct SimpleRange | |
− | struct | + | |
{ | { | ||
− | + | int* begin(); | |
+ | int* end(); | ||
}; | }; | ||
− | static_assert(std::ranges::range< | + | static_assert(std::ranges::range<SimpleRange>); |
− | + | // Not a range: no begin/end | |
+ | struct NotRange | ||
{ | { | ||
− | + | int t {}; | |
}; | }; | ||
− | static_assert( | + | static_assert(!std::ranges::range<NotRange>); |
− | + | ||
− | + | // Not a range: begin does not return an input_or_output_iterator | |
+ | struct NotRange2 | ||
{ | { | ||
− | + | void* begin(); | |
− | + | int* end(); | |
+ | }; | ||
+ | static_assert(!std::ranges::range<NotRange2>); | ||
− | + | int main() {} | |
− | + | ||
− | } | + | |
− | + | ||
− | + | ||
− | + | ||
}} | }} | ||
+ | |||
+ | ===Defect reports=== | ||
+ | {{dr list begin}} | ||
+ | {{dr list item|wg=lwg|dr=3915|std=C++20|before={{c|ranges::begin(t)}} and {{c|ranges::end(t)}}<br>did not require implicit expression variations|after=removed the<br>redundant description}} | ||
+ | {{dr list end}} | ||
{{langlinks|es|ja|ru|zh}} | {{langlinks|es|ja|ru|zh}} |
Latest revision as of 07:54, 25 July 2024
Defined in header <ranges>
|
||
template< class T > concept range = requires( T& t ) { |
(since C++20) | |
The range
concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range.
Contents |
[edit] Semantic requirements
Given an expression E such that decltype((E)) is T
, T
models range
only if
-
[
ranges::begin(E),
ranges::end(E))
denotes a range, and - both ranges::begin(E) and ranges::end(E) are amortized constant time and do not alter the value of E in a manner observable to equality-preserving expressions, and
- if the type of ranges::begin(E) models
forward_iterator
, ranges::begin(E) is equality-preserving (in other words, forward iterators support multi-pass algorithms).
[edit] Notes
A typical range
class only needs to provide two functions:
- A member function
begin()
whose return type modelsinput_or_output_iterator
. - A member function
end()
whose return type modelssentinel_for
<It>
, whereIt
is the return type ofbegin()
.
Alternatively, they can be non-member functions, to be found by argument-dependent lookup.
[edit] Example
Run this code
#include <ranges> // A minimum range struct SimpleRange { int* begin(); int* end(); }; static_assert(std::ranges::range<SimpleRange>); // Not a range: no begin/end struct NotRange { int t {}; }; static_assert(!std::ranges::range<NotRange>); // Not a range: begin does not return an input_or_output_iterator struct NotRange2 { void* begin(); int* end(); }; static_assert(!std::ranges::range<NotRange2>); int main() {}
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 3915 | C++20 | ranges::begin(t) and ranges::end(t) did not require implicit expression variations |
removed the redundant description |