std::ranges::fold_right(3)
πΈ NAME
Bestie, this is std::ranges::fold_right(3) β the C++ Standard Library algorithm that folds a range from the right side. Yes, the NAME section is literally std::ranges::fold_right - std::ranges::fold_right, because manpages love a little mirror selfie moment. π
β¨ Synopsis
Defined in header <algorithm>.
Call signature β okay, here's the whole lineup, no crumbs:
template< std::bidirectional_iterator I,
std::sentinel_for<I> S, class T,
/* indirectly-binary-right-foldable */<T, I> F >
constexpr auto fold_right( I first, S last, T init, F f );
// (since C++23)
// (until C++26)
template< std::bidirectional_iterator I,
std::sentinel_for<I> S,
class T = std::iter_value_t<I>,
/* indirectly-binary-right-foldable */<T, I> F >
constexpr auto fold_right( I first, S last, T init, F f );
// (since C++26)
template< ranges::bidirectional_range R, class T,
/* indirectly-binary-right-foldable */<T, ranges::iterator_t<R>> F >
constexpr auto fold_right( R&& r, T init, F f );
// (1)
// (since C++23)
// (until C++26)
template< ranges::bidirectional_range R, class T =
ranges::range_value_t<R>,
/* indirectly-binary-right-foldable */<T, ranges::iterator_t<R>> F >
constexpr auto fold_right( R&& r, T init, F f );
// (2)
// (since C++26)
π§ Helper concepts
template< class F, class T, class I >
concept /* indirectly-binary-left-foldable */ = /* see description */; // (3)
template< class F, class T, class I >
concept /* indirectly-binary-right-foldable */ = /* see description */; // (4)
Right-folds the elements of the given range, meaning it returns the result of evaluating the chain expression:
f(x[1], f(x[2], ...f(x[n], init)))
where x[1], x[2], ..., x[n] are elements of the range.
Informally, ranges::fold_right behaves like std::fold_left(ranges::reverse(r), init, /* flipped */(f)).
π¨ Real talk: the behavior is undefined if [first, last) is not a valid range. Not cute, not safe, not iconic. Validate your range, bestie.
- The range is
[first, last). - Same as (1), except that it uses
ras the range, as if by usingranges::begin(r)asfirstandranges::end(r)aslast. - Equivalent to:
template< class F, class T, class I, class U >
concept /*indirectly-binary-left-foldable-impl*/ =
std::movable<T> &&
std::movable<U> &&
std::convertible_to<T, U> &&
std::invocable<F&, U, std::iter_reference_t<I>> &&
std::assignable_from<U&,
std::invoke_result_t<F&, U, std::iter_reference_t<I>>>;
(3A) (exposition only*)
template< class F, class T, class I >
concept /*indirectly-binary-left-foldable*/ =
std::copy_constructible<F> &&
std::indirectly_readable<I> &&
std::invocable<F&, T, std::iter_reference_t<I>> &&
std::convertible_to<std::invoke_result_t<F&, T,
std::iter_reference_t<I>>,
std::decay_t<std::invoke_result_t<F&, T,
std::iter_reference_t<I>>>> &&
/*indirectly-binary-left-foldable-impl*/<F, T, I,
std::decay_t<std::invoke_result_t<F&, T,
std::iter_reference_t<I>>>>;
(3B) (exposition only*)
- Equivalent to:
template< class F, class T, class I >
concept /*indirectly-binary-right-foldable*/ =
/*indirectly-binary-left-foldable*/</*flipped*/<F>, T, I>;
(4A) (exposition only*)
Helper class templates
template< class F >
class /*flipped*/
{
F f; // exposition only
public:
template< class T, class U >
requires std::invocable<F&, U, T>
std::invoke_result_t<F&, U, T> operator()( T&&, U&& );
};
(4B) (exposition only*)
The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
In practice, they may be implemented as function objects, or with special compiler extensions. Slay, but make it compiler-internal. β¨
π Parameters
first,lastβ the range of elements to fold.rβ the range of elements to fold.initβ the initial value of the fold.fβ the binary function object.
π«Ά Return value
An object of type U that contains the result of the right-fold of the given range over f, where U is equivalent to std::decay_t<std::invoke_result_t<F&, std::iter_reference_t<I>, T>>;. Yes, that trailing semicolon is part of the vibe. Keep it.
If the range is empty, U(std::move(init)) is returned.
π Possible implementations
struct fold_right_fn
{
template<std::bidirectional_iterator I, std::sentinel_for<I> S,
class T = std::iter_value_t<I>,
/* indirectly-binary-right-foldable */<T, I> F>
constexpr auto operator()(I first, S last, T init, F f) const
{
using U = std::decay_t<std::invoke_result_t<F&,
std::iter_reference_t<I>, T>>;
if (first == last)
return U(std::move(init));
I tail = ranges::next(first, last);
U accum = std::invoke(f, *--tail, std::move(init));
while (first != tail)
accum = invoke(f, *--tail, std::move(accum));
return accum;
}
template<ranges::bidirectional_range R, class T =
ranges::range_value_t<R>,
/* indirectly-binary-right-foldable */<T,
ranges::iterator_t<R>> F>
constexpr auto operator()(R&& r, T init, F f) const
{
return (*this)(ranges::begin(r), ranges::end(r),
std::move(init), std::ref(f));
}
};
inline constexpr fold_right_fn fold_right;
π₯ Complexity
Exactly ranges::distance(first, last) applications of the function object f. No extra, no less β that's the whole budget. π
π Notes
The following table compares all constrained folding algorithms. Terminal table said "no tables," so here's the bullet-list remix:
ranges::fold_leftβ starts from left, initial valueinit, return typeU.ranges::fold_left_firstβ starts from left, initial value first element, return typestd::optional<U>.ranges::fold_rightβ starts from right, initial valueinit, return typeU.ranges::fold_right_lastβ starts from right, initial value last element, return typestd::optional<U>.ranges::fold_left_with_iterβ starts from left, initial valueinit, return type:(1)ranges::in_value_result<I, U>(2)ranges::in_value_result<BR, U>, whereBRisranges::borrowed_iterator_t<R>
ranges::fold_left_first_with_iterβ starts from left, initial value first element, return type:(1)ranges::in_value_result<I, std::optional<U>>(2)ranges::in_value_result<BR, std::optional<U>>, whereBRisranges::borrowed_iterator_t<R>
Feature-test macro
__cpp_lib_ranges_foldβ value202207Lβ std(C++23)β featurestd::ranges fold algorithms__cpp_lib_algorithm_default_value_typeβ value202403β std(C++26)β featureList-initialization for algorithms (1,2)
π Example
Run this code, bestie β it's giving demo energy:
#include <algorithm>
#include <complex>
#include <functional>
#include <iostream>
#include <ranges>
#include <string>
#include <utility>
#include <vector>
using namespace std::literals;
namespace ranges = std::ranges;
int main()
{
auto v = {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<std::string> vs{"A", "B", "C", "D"};
auto r1 = ranges::fold_right(v.begin(), v.end(), 6, std::plus<>()); // (1)
std::cout << "r1: " << r1 << '\n';
auto r2 = ranges::fold_right(vs, "!"s, std::plus<>()); // (2)
std::cout << "r2: " << r2 << '\n';
// Use a program defined function object (lambda-expression):
std::string r3 = ranges::fold_right
(
v, "A", [](int x, std::string s) { return s + ':' + std::to_string(x); }
);
std::cout << "r3: " << r3 << '\n';
// Get the product of the std::pair::second of all pairs in the vector:
std::vector<std::pair<char, float>> data{{'A', 2.f}, {'B', 3.f}, {'C', 3.5f}};
float r4 = ranges::fold_right
(
data | ranges::views::values, 2.0f, std::multiplies<>()
);
std::cout << "r4: " << r4 << '\n';
using CD = std::complex<double>;
std::vector<CD> nums{{1, 1}, {2, 0}, {3, 0}};
#ifdef __cpp_lib_algorithm_default_value_type
auto r5 = ranges::fold_right(nums, {7, 0}, std::multiplies{});
#else
auto r5 = ranges::fold_right(nums, CD{7, 0}, std::multiplies{});
#endif
std::cout << "r5: " << r5 << '\n';
}
π¦ Output
r1: 42
r2: ABCD!
r3: A:8:7:6:5:4:3:2:1
r4: 42
r5: (42,42)
β References
- C++23 standard (ISO/IEC 14882:2023):
- 27.6.18 Fold [alg.fold]
π«Ά See also π«Ά
okay bestie, you made it to the see-also corner β these are the related pages, and yes, the whole fold crew is here π
ranges::fold_right_last(C++23) β right-folds a range of elements using the last element as an initial value. It's a niebloid β¨ranges::fold_left(C++23) β left-folds a range of elements. Also a niebloid πranges::fold_left_first(C++23) β left-folds a range of elements using the first element as an initial value, and it's a niebloid π¦ranges::fold_left_with_iter(C++23) β left-folds a range of elements, and returns a pair (iterator,value). Niebloid energy, periodt πranges::fold_left_first_with_iter(C++23) β left-folds a range of elements using the first element as an initial value, and returns a pair (iterator,optional). Niebloid πaccumulateβ sums up or folds a range of elements. It's a function template πΈreduce(C++17) β similar tostd::accumulate, except out of order. Also a function template π₯
lowkey this is the whole reference list β no cap, nothing skipped π«Ά
okay that's the page!! sourced from http://cppreference.com, date 2024.06.10, and the page is std::ranges::fold_right(3) β mwah, go fold something cute π
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms