RANGES
RANGES
// rangesFilterTransform.cpp
#include <iostream>
#include <ranges>
#include <vector>
int main() {
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::all_view, std::views::all // takes all elements
The following example uses a lambda expression to increment all of the elements of a vector
and then uses an overloaded operator() in a functor to compute their sum. Note that to compute
the sum, it is recommended to use the dedicated algorithm std::accumulate.
struct Sum
{
void operator()(int n) { sum += n; }
int sum {0};
};
int main()
{
std::vector<int> nums {3, 4, 2, 8, 15, 267};
before: 3 4 2 8 15 267
after: 4 5 3 9 16 268
sum: 305
project the pair::first: 1 2 3
project the pair::second: one two tree
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::all_of
Parameters
first, last - the range of the elements to examine
r - the range of the elements to examine
pred - predicate to apply to the projected elements
proj - projection to apply to the elements
Return value
1,2) true if std::invoke(pred, std::invoke(proj, *i)) != false for every iterator i in the range, false
otherwise. Returns true if the range is empty.
Example
Run this code
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
std::vector<int> v(10, 2);
std::partial_sum(v.cbegin(), v.cend(), v.begin());
std::cout << "Among the numbers: ";
ranges::copy(v, std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
if (ranges::none_of(v, std::bind(std::modulus<int>(),
std::placeholders::_1, 2)))
std::cout << "None of them are odd\n";
auto DivisibleBy = [](int d)
{
return [d](int m) { return m % d == 0; };
};
if (ranges::any_of(v, DivisibleBy(7)))
std::cout << "At least one number is divisible by 7\n";
}
Output:
Among the numbers: 2 4 6 8 10 12 14 16 18 20
All numbers are even
None of them are odd
At least one number is divisible by 7
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::find, std::ranges::find_if, std::ranges::find_if_not
Parameters
first, last - the range of elements to examine
r - the range of the elements to examine
value - value to compare the elements to
pred - predicate to apply to the projected elements
proj - projection to apply to the elements
Return value
Iterator to the first element satisfying the condition or iterator equal to last if no such element is
found.
Example
Run this code
#include <algorithm>
#include <format>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
void projector_example()
{
struct folk_info
{
unsigned uid;
std::string name, position;
};
std::vector<folk_info> folks
{
{0, "Ana", "dev"},
{1, "Bob", "devops"},
{2, "Eve", "ops"}
};
int main()
{
namespace ranges = std::ranges;
projector_example();
const int n1 = 3;
const int n2 = 5;
const auto v = {4, 1, 3, 2};
Output:
Profile:
UID: 2
Name: Eve
Position: ops
v contains: 3
v does not contain: 5
First even element in v: 4
First odd element in v: 1
No elements in v are divisible by 13
First element indivisible by 13 in v: 4
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::count, std::ranges::count_if
Parameters
first, last - the range of elements to examine
r - the range of the elements to examine
value - the value to search for
pred - predicate to apply to the projected elements
proj - projection to apply to the elements
Return value
Number of elements satisfying the condition.
Example
Run this code
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3, 4, 4, 3, 7, 8, 9, 10};
Output:
number: 3 count: 2
number: 5 count: 0
number divisible by three: 3
number divisible by eleven: 0
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::mismatch
Parameters
first1, last1 - an iterator-sentinel pair denoting the first range of the elements to
compare
r1 - the first range of the elements to compare
first2, last2 - an iterator-sentinel pair denoting the second range of the elements to
compare
r2 - the second range of the elements to compare
pred - predicate to apply to the projected elements
proj1 - projection to apply to the first range of elements
proj2 - projection to apply to the second range of elements
Return value
ranges::mismatch_result with iterators to the first two non-equal elements.
If no mismatches are found when the comparison reaches last1 or last2, whichever happens
first, the object holds the end iterator and the corresponding iterator from the other range.
Example
This program determines the longest substring that is simultaneously found at the very beginning and at the
very end of the given string, in reverse order (possibly overlapping).
[[nodiscard]]
constexpr std::string_view mirror_ends(const std::string_view in)
{
const auto end = std::ranges::mismatch(in, in | std::views::reverse).in1;
return {in.cbegin(), end};
}
int main()
{
std::cout << mirror_ends("abXYZba") << '\n'
<< mirror_ends("abca") << '\n'
<< mirror_ends("ABBA") << '\n'
<< mirror_ends("level") << '\n';
static_assert("123"sv == mirror_ends("123!@#321"));
static_assert("radar"sv == mirror_ends("radar"));
}
Output:
ab
a
ABBA
level
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::equal
Parameters
first1, last1 - an iterator-sentinel pair denoting the first range of the elements to
compare
r1 - the first range of the elements to compare
first2, last2 - an iterator-sentinel pair denoting the second range of the elements to
compare
r2 - the second range of the elements to compare
pred - predicate to apply to the projected elements
proj1 - projection to apply to the first range of elements
proj2 - projection to apply to the second range of elements
Return value
If the length of the range [first1, last1) does not equal the length of the range [first2, last2),
returns false.
If the elements in the two ranges are equal after projection, returns true.
Otherwise returns false.
Example
The following code uses ranges::equal to test if a string is a palindrome.
int main()
{
test("radar");
test("hello");
static_assert(is_palindrome("ABBA") and not is_palindrome("AC/DC"));
}
Output:
"radar" is a palindrome
"hello" is not a palindrome
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::copy, std::ranges::copy_if
Parameters
first, last - the range of elements to copy
r - the range of elements to copy
result - the beginning of the destination range.
pred - predicate to apply to the projected elements
proj - projection to apply to the elements
Return value
A ranges::in_out_result containing an input iterator equal to last and an output iterator past the
last element copied.
Example
The following code uses ranges::copy to both copy the contents of one std::vector to another and to
display the resulting std::vector:
int main()
{
std::vector<int> source(10);
std::iota(source.begin(), source.end(), 0);
std::vector<int> destination;
std::ranges::copy(source.begin(), source.end(),
std::back_inserter(destination));
// or, alternatively,
// std::vector<int> destination(source.size());
// std::ranges::copy(source.begin(), source.end(), destination.begin());
// either way is equivalent to
// std::vector<int> destination = source;
Output:
destination contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in destination are: 1 3 5 7 9
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::transform
Parameters
first1, last1 - the first range of elements to transform
r, r1 - the first range of elements to transform
first2, last2 - the second range of elements to transform
r2 - the second range of elements to transform
result - the beginning of the destination range, may be equal to first1 or first2
op, binary_op - operation to apply to the projected element(s)
proj1 - projection to apply to the elements in the first range
proj2 - projection to apply to the elements in the second range
Return value
1,2) A unary_transform_result contains an input iterator equal to last and an output iterator to
the element past the last element transformed.
Example
The following code uses ranges::transform to convert a string in place to uppercase using the
std::toupper function and then transforms each char to its ordinal value. Then ranges::transform
with a projection is used to transform elements of std::vector<Foo> into chars to fill a std::string.
int main()
{
std::string s{"hello"};
auto op = [](unsigned char c) -> unsigned char { return std::toupper(c); };
std::vector<std::size_t> ordinals;
// convert each char to size_t
ranges::transform(s, std::back_inserter(ordinals),
[](unsigned char c) -> std::size_t { return c; });
Output:
HELLO: 72 69 76 76 79
144 138 152 152 158
HELLO
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::replace
Parameters
first, last - the range of elements to process
r - the range of elements to process
old_value - the value of elements to replace
new_value - the value to use as a replacement
pred - predicate to apply to the projected elements
proj - projection to apply to the elements
Return value
An iterator equal to last.
Example
Run this code
#include <algorithm>
#include <array>
#include <iostream>
int main()
{
auto print = [](const auto& v)
{
for (const auto& e : v)
std::cout << e << ' ';
std::cout << '\n';
};
Output:
1 6 1 6 1 6
1 9 1 9 1 9
1 2 3 6 7 8 4 5
1 2 3 5 5 5 4 5
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::replace_copy, std::replace_copy_if
Parameters
first, last - the range of elements to copy
d_first - the beginning of the destination range
old_value - the value of elements to replace
policy - the execution policy to use. See execution policy for details.
p - unary predicate which returns true if the element value should be replaced.
The expression p(v) must be convertible to bool for every argument v of type (possibly const)
VT, where VT is the value type of InputIt, regardless of value category, and must not modify v.
Thus, a parameter type of VT&is not allowed, nor is VT unless for VT a move is equivalent to a
copy(since C++11).
Example
The following copy-prints a vector, replacing all values over 5 with 99 on the fly.
int main()
{
std::vector<int> v{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
std::replace_copy_if(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, " "),
[](int n){ return n > 5; }, 99);
std::cout << '\n';
}
Output:
5 99 4 2 99 99 1 99 0 3
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::fill
Parameters
first, last - the range of elements to modify
r - the range of elements to modify
value - the value to be assigned
Return value
An output iterator that compares equal to last.
Example
The following code uses ranges::fill to set all elements of std::vector<int> first to -1, then to 10.
int main()
{
std::vector<int> v {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
std::ranges::fill(v, 10);
println(v);
}
Output:
-1 -1 -1 -1 -1 -1 -1 -1 -1 -1
10 10 10 10 10 10 10 10 10 10
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::generate
Parameters
first, last - the range of elements to modify
r - the range of elements to modify
gen - the generator function object
Return value
An output iterator that compares equal to last.
Example
Run this code
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string_view>
auto dice()
{
static std::uniform_int_distribution<int> distr {1, 6};
static std::random_device device;
static std::mt19937 engine {device()};
return distr(engine);
}
int main()
{
std::array<int, 8> v;
iota(v, 1);
print("iota: ", v);
}
Possible output:
dice: 4 3 1 6 6 4 5 5
dice: 4 2 5 3 6 2 6 2
iota: 1 2 3 4 5 6 7 8
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::remove_copy, std::ranges::remove_copy_if
Parameters
first, last - the source range of elements
r - the source range of elements
result - the beginning of the destination range
value - the value of the elements not to copy
comp - the binary predicate to compare the projected elements
proj - the projection to apply to the elements
Return value
{last, result + N}, where N is the number of elements copied.
Example
Run this code
#include <algorithm>
#include <array>
#include <complex>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <string_view>
#include <vector>
int main()
{
// Filter out the hash symbol from the given string.
const std::string_view str{"#Small #Buffer #Optimization"};
std::cout << "before: " << std::quoted(str) << '\n';
std::ranges::remove_copy_if(
source,
std::back_inserter(target),
[](int imag) { return imag <= 0; },
[](Ci z) { return z.imag(); }
);
print("source:", source);
print("target:", target);
}
Output:
before: "#Small #Buffer #Optimization"
after: "Small Buffer Optimization"
source: (1,0) (0,1) (2,-1) (3,2) (4,-3)
target: (0,1) (3,2)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::unique
Parameters
first, last - the range of elements to process
r - the range of elements to process
comp - the binary predicate to compare the projected elements
proj - the projection to apply to the elements
Return value
Returns {ret, last}, where ret is a past-the-end iterator for the new end of the range.
Example
Run this code
#include <algorithm>
#include <cmath>
#include <complex>
#include <iostream>
#include <vector>
struct id {
int i;
explicit id(int i) : i {i} {}
};
int main()
{
// a vector containing several duplicated elements
std::vector<int> v {1, 2, 1, 1, 3, 3, 3, 4, 5, 4};
Output:
1) 1 2 1 1 3 3 3 4 5 4
2) 1 2 1 3 4 5 4
3) 1 1 2 3 4 4 5
4) 1 2 3 4 5
5) (1,1) (-1,2) (-2,3) (2,4) (-3,5)
6) (1,1) (-2,3) (-3,5)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::reverse
Parameters
first, last - the range of elements to reverse
r - the range of elements to reverse
Return value
An iterator equal to last.
Example
Run this code
#include <algorithm>
#include <array>
#include <iostream>
#include <string>
int main()
{
std::string s {"ABCDEF"};
std::cout << s << " → ";
std::ranges::reverse(s.begin(), s.end());
std::cout << s << " → ";
std::ranges::reverse(s);
std::cout << s << " │ ";
Output:
ABCDEF → FEDCBA → ABCDEF │ 1 2 3 4 5 → 5 4 3 2 1
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::rotate
Parameters
first, last - the range of elements to rotate
r - the range of elements to rotate
middle - the iterator to the element that should appear at the beginning of the rotated
range
Return value
{new_first, last}, where new_first compares equal to ranges::next(first, ranges::distance(middle,
last)) and designates a new location of the element pointed by first
Example
ranges::rotate is a common building block in many algorithms. This example demonstrates insertion sort.
int main()
{
std::string s(16, ' ');
s = {'2', '4', '2', '0', '5', '9', '7', '3', '7', '1'};
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::sort
Parameters
first, last - iterator-sentinel defining the range to sort
r - the range to sort
comp - comparison to apply to the projected elements
proj - projection to apply to the elements
Return value
An iterator equal to last.
Example
Run this code
#include <algorithm>
#include <array>
#include <functional>
#include <iomanip>
#include <iostream>
void print(auto comment, auto const& seq, char term = ' ')
{
for (std::cout << comment << '\n'; auto const& elem : seq)
std::cout << elem << term;
std::cout << '\n';
}
struct Particle
{
std::string name; double mass; // MeV
template<class Os> friend
Os& operator<<(Os& os, Particle const& p)
{
return os << std::left << std::setw(8) << p.name << " : " << p.mass <<
' ';
}
};
int main()
{
std::array s {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
ranges::sort(s);
print("Sort using the default operator<", s);
ranges::sort(s, ranges::greater());
print("Sort using a standard library compare function object", s);
struct
{
bool operator()(int a, int b) const { return a < b; }
} customLess;
ranges::sort(s.begin(), s.end(), customLess);
print("Sort using a custom function object", s);
Particle particles[]
{
{"Electron", 0.511}, {"Muon", 105.66}, {"Tau", 1776.86},
{"Positron", 0.511}, {"Proton", 938.27}, {"Neutron", 939.57}
};
ranges::sort(particles, {}, &Particle::name);
print("\nSort by name using a projection", particles, '\n');
ranges::sort(particles, {}, &Particle::mass);
print("Sort by mass using a projection", particles, '\n');
}
Output:
Sort using the default operator<
0 1 2 3 4 5 6 7 8 9
Sort using a standard library compare function object
9 8 7 6 5 4 3 2 1 0
Sort using a custom function object
0 1 2 3 4 5 6 7 8 9
Sort using a lambda expression
9 8 7 6 5 4 3 2 1 0
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::merge
Parameters
first1, last1 - the first input sorted range
first2, last2 - the second input sorted range
result - the beginning of the output range
comp - comparison to apply to the projected elements
proj1 - projection to apply to the elements in the first range
proj2 - projection to apply to the elements in the second range
Return value
{last1, last2, result_last}, where result_last is the end of the constructed range.
Example
Run this code
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
void print(const auto& in1, const auto& in2, auto first, auto last)
{
std::cout << "{ ";
for (const auto& e : in1)
std::cout << e << ' ';
std::cout << "} +\n{ ";
for (const auto& e : in2)
std::cout << e << ' ';
std::cout << "} =\n{ ";
while (!(first == last))
std::cout << *first++ << ' ';
std::cout << "}\n\n";
}
int main()
{
std::vector<int> in1, in2, out;
Output:
{ 1 2 3 4 5 } +
{ 3 4 5 6 7 } =
{ 1 2 3 3 4 4 5 5 6 7 }
{ 1 2 3 4 5 5 5 } +
{ 3 4 5 6 7 } =
{ 1 2 3 3 4 4 5 5 5 5 6 7 }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::max
Parameters
a, b - the values to compare
r - the range of values to compare
comp - comparison to apply to the projected elements
proj - projection to apply to the elements
Return value
1) The greater of a and b, according to their respective projected values. If they are equivalent,
returns a.
2,3) The greatest value in r, according to the projection. If several values are equivalent to the
greatest, returns the leftmost one. If the range is empty (as determined by ranges::distance(r)),
the behavior is undefined.
Example
Run this code
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
namespace ranges = std::ranges;
using namespace std::string_view_literals;
std::cout << "larger of 1 and 9999: " << ranges::max(1, 9999) << '\n'
<< "larger of 'a', and 'b': '" << ranges::max('a', 'b') << "'\n"
<< "longest of \"foo\", \"bar\", and \"hello\": \""
<< ranges::max({"foo"sv, "bar"sv, "hello"sv}, {},
&std::string_view::size) << "\"\n";
}
Output:
larger of 1 and 9999: 9999
larger of 'a', and 'b': 'b'
longest of "foo", "bar", and "hello": "hello"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::min
Parameters
a, b - the values to compare
r - the range of values to compare
comp - comparison to apply to the projected elements
proj - projection to apply to the elements
Return value
1) The smaller of a and b, according to the projection. If they are equivalent, returns a.
2,3) The smallest element in r, according to the projection. If several values are equivalent to the
smallest, returns the leftmost one. If the range is empty (as determined by ranges::distance(r)),
the behavior is undefined.
Example
Run this code
#include <algorithm>
#include <iostream>
#include <string>
int main()
{
namespace ranges = std::ranges;
using namespace std::string_view_literals;
std::cout << "smaller of 1 and 9999: " << ranges::min(1, 9999) << '\n'
<< "smaller of 'a', and 'b': '" << ranges::min('a', 'b') << "'\n"
<< "shortest of \"foo\", \"bar\", and \"hello\": \""
<< ranges::min({"foo"sv, "bar"sv, "hello"sv}, {},
&std::string_view::size) << "\"\n";
}
Output:
smaller of 1 and 9999: 1
smaller of 'a', and 'b': 'a'
shortest of "foo", "bar", and "hello": "foo"
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
std::ranges::lexicographical_compare
Parameters
first1, last1 - the first range of elements to examine
r1 - the first range of elements to examine
first2, last2 - the second range of elements to examine
r2 - the second range of elements to examine
comp - comparison function to apply to the projected elements
proj1 - projection to apply to the first range of elements
proj2 - projection to apply to the second range of elements
Return value
true if the first range is lexicographically less than the second.
Example
Run this code
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <vector>
int main()
{
std::vector<char> v1 {'a', 'b', 'c', 'd'};
std::vector<char> v2 {'a', 'b', 'c', 'd'};
ranges::shuffle(v1, g);
ranges::shuffle(v2, g);
}
ranges::copy(v1, os);
std::cout << "< ";
ranges::copy(v2, os);
std::cout << '\n';
}
Possible output:
a b c d >= a b c d
d a b c >= c b d a
b d a c >= a d c b
a c d b < c d a b
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
Std::ranges::iota
Parameters
first, last - the range of elements to fill with sequentially increasing values starting
with value
value - initial value to store; the expression ++value must be well-formed
Return value
{last, value + ranges::distance(first, last)}
Example
Uses the vector of iterators (std::vector<std::list<T>::iterator>) as a proxy to shuffle the
elements of the std::list, because ranges::shuffle cannot be applied to the std::list directly.
int main()
{
std::list<int> list(8);
Possible output:
List: 0 1 2 3 4 5 6 7
List viewed via vector: 5 7 6 0 1 3 4 2