Difference between revisions of "cpp/ranges/range"
From cppreference.com
(mention how to make a class satisfy this concept) |
(Added LWG issue #3915 DR.) |
||
Line 16: | Line 16: | ||
===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 37: | Line 36: | ||
#include <vector> | #include <vector> | ||
− | template <typename T> | + | template<typename T> |
struct range_t : private T | struct range_t : private T | ||
{ | { | ||
− | using T::begin, T::end; /*...*/ | + | using T::begin, T::end; /* ... */ |
}; | }; | ||
− | static_assert(std::ranges::range< range_t<std::vector<int>> >); | + | static_assert(std::ranges::range<range_t<std::vector<int>>>); |
− | template <typename T> struct scalar_t | + | template<typename T> |
+ | struct scalar_t | ||
{ | { | ||
T t {}; /* no begin/end */ | T t {}; /* no begin/end */ | ||
}; | }; | ||
− | static_assert(not std::ranges::range< scalar_t<int> >); | + | static_assert(not std::ranges::range<scalar_t<int>>); |
int main() | int main() | ||
Line 54: | Line 54: | ||
if constexpr (range_t<std::vector<int>> r; std::ranges::range<decltype(r)>) | if constexpr (range_t<std::vector<int>> r; std::ranges::range<decltype(r)>) | ||
std::cout << "r is a range\n"; | std::cout << "r is a range\n"; | ||
− | + | ||
if constexpr (scalar_t<int> s; not std::ranges::range<decltype(s)>) | if constexpr (scalar_t<int> s; not std::ranges::range<decltype(s)>) | ||
std::cout << "s is not a range\n"; | std::cout << "s is not a range\n"; | ||
Line 62: | Line 62: | ||
s is not a range | s is not a range | ||
}} | }} | ||
+ | |||
+ | ===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}} |
Revision as of 17:51, 6 November 2023
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 |
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).
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.
Example
Run this code
#include <iostream> #include <ranges> #include <vector> template<typename T> struct range_t : private T { using T::begin, T::end; /* ... */ }; static_assert(std::ranges::range<range_t<std::vector<int>>>); template<typename T> struct scalar_t { T t {}; /* no begin/end */ }; static_assert(not std::ranges::range<scalar_t<int>>); int main() { if constexpr (range_t<std::vector<int>> r; std::ranges::range<decltype(r)>) std::cout << "r is a range\n"; if constexpr (scalar_t<int> s; not std::ranges::range<decltype(s)>) std::cout << "s is not a range\n"; }
Output:
r is a range s is not a range
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 |