Namespaces
Variants

std::ranges::fold_left

출처 ko.cppreference.net
 
 
알고리즘 라이브러리
제약된 알고리즘 및 범위에 대한 알고리즘 (C++20)
제약된 알고리즘, 예: ranges::copy, ranges::sort, ...
정렬 및 관련 연산
분할 연산
(C++11)    

정렬 연산
이진 탐색 연산
(분할된 범위에 대해)
집합 연산 (정렬된 범위에 대해)
병합 연산 (정렬된 범위에 대해)
힙 연산
최소/최대 연산
(C++11)
(C++17)
사전식 비교 연산
순열 연산


 
제약된 알고리즘
이 메뉴의 모든 이름은 네임스페이스 std::ranges
비수정 시퀀스 연산
수정 시퀀스 연산
분할 연산
정렬 연산
이진 탐색 연산 (정렬된 범위에 대해)
       
       
집합 연산 (정렬된 범위에 대해)
힙 연산
최소/최대 연산
       
       
순열 연산
폴드 연산
수치 연산
(C++23)            
초기화되지 않은 저장소에 대한 연산
반환 타입
 
헤더에 정의됨 <algorithm>
호출 시그니처
template< std::input_iterator I, std::sentinel_for<I> S, class T,
          /* indirectly-binary-left-foldable */<T, I> F >
constexpr auto fold_left( I first, S last, T init, F f );
(1) (C++23부터)
(C++26까지)
template< std::input_iterator I, std::sentinel_for<I> S,
          class T = std::iter_value_t<I>,
          /* indirectly-binary-left-foldable */<T, I> F >
constexpr auto fold_left( I first, S last, T init, F f );
(C++26부터)
template< ranges::input_range R, class T,
          /* indirectly-binary-left-foldable */
              <T, ranges::iterator_t<R>> F >
constexpr auto fold_left( R&& r, T init, F f );
(2) (C++23부터)
(C++26까지)
template< ranges::input_range R, class T = ranges::range_value_t<R>,
          /* indirectly-binary-left-foldable */
              <T, ranges::iterator_t<R>> F >
constexpr auto fold_left( R&& r, T init, F f );
(C++26부터)
헬퍼 개념
template< class F, class T, class I >
concept /* indirectly-binary-left-foldable */ = /* see description */;
(3) (설명 전용*)

왼쪽-폴드 주어진 범위의 요소들을, 즉 체인 표현식의 평가 결과를 반환합니다:
f(f(f(f(init, x1), x2), ...), xn), 여기서 x1, x2, ..., xn는 범위의 요소들입니다.

비공식적으로, ranges::fold_left는 다음과 같이 동작합니다 std::accumulate의 이진 조건자를 받는 오버로드.

다음의 경우 동작이 정의되지 않습니다: [first, last)가 유효한 범위가 아닌 경우.

1) 범위는 [first, last)입니다. 다음과 동등: return ranges::fold_left_with_iter(std::move(first), last, std::move(init), f).value.
2) 와 동일하나, (1), 대신 r를 범위로 사용하는 점이 다릅니다. 마치 ranges::begin(r)를 first 및 ranges::end(r)로 사용하는 것과 같습니다.last.
3) 다음에 동등:
헬퍼 개념
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) (설명 전용*)
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) (설명 전용*)

이 페이지에 설명된 함수형 엔티티들은 알고리즘 함수 객체 (비공식적으로 niebloids라고 함), 즉:

매개변수

first, last - 폴드할 요소들의 범위 를 정의하는 반복자-센티넬 쌍
r - 폴드할 요소들의 범위
init - 폴드의 초기값
f - 이항 함수 객체

반환값

주어진 범위에 대해 f 를 사용한 왼쪽- 폴드 의 결과를 포함하는 U 타입의 객체. 여기서 U 는 std:: decay_t < std:: invoke_result_t < F & , T, std:: iter_reference_t < I >>> 와 동등합니다.

범위가 비어 있으면, U ( std :: move ( init ) ) 가 반환됩니다.

가능한 구현

struct fold_left_fn
{
    template<std::input_iterator I, std::sentinel_for<I> S, class T = std::iter_value_t<I>,
             /* 간접적으로-이항-좌측-접기-가능 */<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&, T, std::iter_reference_t<I>>>;
        if (first == last)
            return U(std::move(init));
        U accum = std::invoke(f, std::move(init), *first);
        for (++first; first != last; ++first)
            accum = std::invoke(f, std::move(accum), *first);
        return std::move(accum);
    }
    template<ranges::input_range R, class T = ranges::range_value_t<R>,
             /* 간접적으로-이항-좌측-접기-가능 */<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_left_fn fold_left;

복잡도

정확히 ranges:: distance ( first, last ) 번 함수 객체 f 가 적용됩니다.

참고 사항

다음 표는 모든 제약 조건을 가진 폴딩 알고리즘들을 비교한 것입니다:

폴드 함수 템플릿 시작 방향 초기값 반환 타입
ranges :: fold_left 왼쪽 init U
ranges:: fold_left_first 왼쪽 첫 번째 요소 std:: optional < U >
ranges:: fold_right 오른쪽 init U
ranges:: fold_right_last 오른쪽 마지막 요소 std:: optional < U >
ranges:: fold_left_with_iter 왼쪽 init

(1) ranges:: in_value_result < I, U >

(2) ranges:: in_value_result < BR, U > ,

여기서 BR 은 ranges:: borrowed_iterator_t < R >

ranges:: fold_left_first_with_iter 왼쪽 첫 번째 요소

(1) ranges:: in_value_result < I, std:: optional < U >>

(2) ranges:: in_value_result < BR, std:: optional < U >>

여기서 BR 은 ranges:: borrowed_iterator_t < R >

기능 테스트 매크로 값 표준 기능
__cpp_lib_ranges_fold 202207L (C++23) std::ranges 폴드 알고리즘
__cpp_lib_algorithm_default_value_type 202403L (C++26) 목록 초기화 for algorithms ( 1,2 )

예제

#include <algorithm>
#include <complex>
#include <functional>
#include <iostream>
#include <ranges>
#include <string>
#include <utility>
#include <vector>
int main()
{
    namespace ranges = std::ranges;
    std::vector v{1, 2, 3, 4, 5, 6, 7, 8};
    int sum = ranges::fold_left(v.begin(), v.end(), 0, std::plus<int>()); // (1)
    std::cout << "sum: " << sum << '\n';
    int mul = ranges::fold_left(v, 1, std::multiplies<int>()); // (2)
    std::cout << "mul: " << mul << '\n';
    // 벡터 내 모든 pair의 std::pair::second 값의 곱을 구함:
    std::vector<std::pair<char, float>> data {{'A', 2.f}, {'B', 3.f}, {'C', 3.5f}};
    float sec = ranges::fold_left
    (
        data | ranges::views::values, 2.0f, std::multiplies<>()
    );
    std::cout << "sec: " << sec << '\n';
    // 프로그램 정의 함수 객체(람다 표현식) 사용:
    std::string str = ranges::fold_left
    (
        v, "A", [](std::string s, int x) { return s + ':' + std::to_string(x); }
    );
    std::cout << "str: " << str << '\n';
    using CD = std::complex<double>;
    std::vector<CD> nums{{1, 1}, {2, 0}, {3, 0}};
    #ifdef __cpp_lib_algorithm_default_value_type
        auto res = ranges::fold_left(nums, {7, 0}, std::multiplies{}); // (2)
    #else
        auto res = ranges::fold_left(nums, CD{7, 0}, std::multiplies{}); // (2)
    #endif
    std::cout << "res: " << res << '\n';
}

출력:

sum: 36
mul: 40320
sec: 42
str: A:1:2:3:4:5:6:7:8
res: (42,42)

참고문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 27.6.18 Fold [alg.fold]

참고 항목

첫 번째 요소를 초기값으로 사용하여 요소 범위를 왼쪽으로 접음
(알고리즘 함수 객체)
요소 범위를 오른쪽으로 접음
(알고리즘 함수 객체)
마지막 요소를 초기값으로 사용하여 요소 범위를 오른쪽으로 접음
(알고리즘 함수 객체)
요소 범위를 왼쪽으로 접고 pair (반복자, 값)을 반환함
(알고리즘 함수 객체)
첫 번째 요소를 초기값으로 사용하여 요소 범위를 왼쪽으로 접고 pair (반복자, optional )을 반환함
(알고리즘 함수 객체)
요소 범위를 합산하거나 접음
(함수 템플릿)
(C++17)
std::accumulate 와 유사하지만 순서가 보장되지 않음
(함수 템플릿)