다음을 통해 공유


<ranges> 뷰 클래스

보기는 소유하지 않는 요소를 참조하는 간단한 범위입니다(제외owning_view). 뷰는 일반적으로 다른 범위를 기반으로 하며, 뷰를 변환하거나 필터링하여 보는 다른 방법을 제공합니다. 예를 들어 std::views::filter 지정한 조건을 사용하여 다른 범위에서 요소를 선택하는 보기가 있습니다.

보기의 요소에 액세스하면 요소가 있는 경우에만 작업이 수행되도록 "지연"으로 수행됩니다. 이렇게 하면 성능 저하 없이 보기를 결합하거나 작성할 수 있습니다.

예를 들어 범위의 짝수 요소만 제공하는 뷰를 만든 다음 제곱하여 변환할 수 있습니다. 필터링 및 변환을 수행하는 작업은 액세스하는 요소와 액세스하는 경우에만 수행됩니다.

뷰는 포함된 요소 수에 관계없이 일정한 시간에 복사, 할당 및 소멸될 수 있습니다. 뷰가 참조하는 요소를 소유하지 않으므로 복사본을 만들 필요가 없기 때문입니다. 성능 저하 없이 보기를 작성할 수 있는 이유입니다.

일반적으로 범위 어댑터를 사용하여 보기를 만듭니다. 범위 어댑터는 뷰를 만드는 의도된 방법이며 보기 클래스를 직접 인스턴스화하는 것보다 사용하기 쉽고 보기 클래스를 직접 인스턴스화하는 것보다 더 효율적일 수 있습니다. 보기 클래스는 기존 뷰 형식을 기반으로 사용자 지정 뷰 형식을 만들어야 하는 경우에 직접 노출됩니다.

다음은 벡터에서 세 개로 나눌 수 있는 요소의 사각형 보기를 만드는 간단한 예입니다.

// requires /std:c++20 or later
#include <ranges>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> input =  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto divisible_by_three = [](const int n) {return n % 3 == 0;};
    auto square = [](const int n) {return n * n;};

    auto x = input
             | std::views::filter(divisible_by_three)
             | std::views::transform(square);

    for (int i : x)
    {
        std::cout << i << ' '; // 0 9 36 81
    }
}
0 9 36 81

기준 범위가 수정된 후 뷰를 사용하면 정의되지 않은 동작이 발생할 수 있습니다. 예를 들어 기본 reverse_view 벡터에서 요소를 추가하거나 제거하는 경우 벡터 기반은 다시 사용하면 안 됩니다. 기본 벡터를 수정하면 뷰가 만들었을 수 있는 반복기의 복사본을 포함하여 컨테이너 end 의 반복기가 무효화됩니다.

보기 만들기가 저렴하기 때문에 기본 범위를 수정하는 경우 일반적으로 뷰를 다시 만들어야 합니다. 다음 예제에서는 다시 사용할 수 있도록 뷰 파이프라인을 변수에 저장하는 방법을 보여 줍니다.

// requires /std:c++20, or later
#include <iostream>
#include <ranges>
#include <vector>
#include <list>
#include <string_view>
#include <algorithm>

template<typename rangeType>
void show(std::string_view msg, rangeType r)
{
    std::cout << msg;
    std::ranges::for_each(r,
        [](auto e)
        {
            std::cout << e << ' ';
        });
    std::cout << '\n';
}

int main()
{
    std::vector v{ 1, 2, 3, 4 };
    show("v: ", v);

    // You can save a view pipeline
    auto rev3 = std::views::take(3) | std::views::reverse;

    show("v | rev3: ", v | rev3); // 3 2 1

    v.insert(v.begin(), 0); // v = 0 1 2 3 4
    show("v: ", v);

    // Because modifying the vector invalidates its iterators, rebuild the view.
    // We are reusing the view pipeline we saved earlier
    show("v | rev3(v): ", rev3(v));
}
v: 1 2 3 4
v | rev3: 3 2 1
v: 0 1 2 3 4
v | rev3(v): 2 1 0

다음 뷰 클래스는 네임스페이 std::ranges 스에 정의되어 있습니다.

보기 설명
basic_istream_viewC++20 입력 스트림의 연속 요소 보기입니다. 전문화에는 포함 istream_viewwistream_view.
common_viewC++20 반복기/sentinel 형식이 다른 뷰를 동일한 반복기/sentinel 형식의 뷰로 조정합니다.
drop_viewC++20 첫 번째 count 요소를 건너뛰고 다른 보기에서 만듭니다.
drop_while_viewC++20 조건자가 보유하는 한 선행 요소를 건너뛰는 다른 보기에서 생성됩니다.
elements_viewC++20 컬렉션의 각 튜플과 유사한 값에 대해 선택한 인덱스 보기입니다. 예를 들어 값 범위 std::tuple<string, int> 가 지정된 경우 각 튜플의 모든 요소로 구성된 뷰를 string 만듭니다.
empty_viewC++20 요소가 없는 뷰입니다.
filter_viewC++20 조건자와 일치하지 않는 범위의 요소를 필터링합니다.
iota_viewC++20 증분 값 시퀀스가 포함된 생성된 뷰입니다.
join_viewC++20 여러 범위의 모든 요소를 단일 보기로 결합합니다.
keys_viewC++20 컬렉션의 각 튜플과 유사한 값에 대한 첫 번째 인덱스 보기입니다. 예를 들어 값 범위 std::tuple<string, int> 가 지정된 경우 각 튜플의 요소로 구성된 뷰를 string 만듭니다.
lazy_split_viewC++20 구분 기호에 따라 보기를 하위 범위로 분할합니다.
owning_viewC++20 다른 범위에서 요소의 소유권을 가져옵니다.
ref_viewC++20 다른 범위에 속하는 요소를 참조하는 뷰입니다.
reverse_viewC++20 범위의 요소를 역순으로 표시합니다.
single_viewC++20 하나의 요소만 포함하는 뷰입니다.
split_viewC++20 구분 기호에 따라 보기를 하위 범위로 분할합니다.
subrangeC++20 시작 반복기 및 센티넬로 정의된 범위 요소의 일부 보기입니다.
take_viewC++20 범위 앞에서 가져온 지정된 개수의 요소를 포함합니다.
take_while_viewC++20 지정된 조건자와 일치하는 범위의 선행 요소를 포함합니다.
transform_viewC++20 변환 함수가 각 요소에 적용된 후의 기본 시퀀스 보기입니다.
values_viewC++20 컬렉션의 각 튜플과 유사한 값에 대한 두 번째 인덱스 보기입니다. 예를 들어 값 범위 std::tuple<string, int> 가 지정된 경우 각 튜플의 요소로 구성된 뷰를 int 만듭니다.

이러한 클래스의 대부분은 네임스페이스에 해당 범위 어댑터를std:views 사용하여 인스턴스를 만듭니다. 뷰 클래스를 직접 만드는 대신 어댑터를 사용하여 보기를 만드는 것이 좋습니다. 범위 어댑터는 보기를 만드는 의도된 방법이며 사용하기 쉬울 수 있으며 경우에 따라 더 효율적입니다.

클래스 특성 보기

각 뷰 클래스 항목에는 구문 섹션 뒤의 특성 섹션이 있습니다. 특성 섹션에는 다음과 같은 항목이 있습니다.

  • 범위 어댑터: 보기를 만드는 범위 어댑터에 대한 링크입니다. 일반적으로 범위 어댑터를 사용하여 보기 클래스를 직접 만드는 대신 보기를 만들 수 있으므로 편의를 위해 여기에 나열됩니다.

  • 기본 범위: 뷰에는 사용할 수 있는 기본 범위의 종류에 대해 서로 다른 반복기 요구 사항이 있습니다. 반복기의 종류에 대한 자세한 내용은 범위 반복기 계층 구조를 참조하세요.

  • 반복기 범주 보기: 뷰의 반복기 범주입니다. 뷰가 범위를 조정하는 경우 뷰의 반복기 형식은 일반적으로 기본 범위의 반복기 형식과 동일합니다. 그러나 일부 보기에서는 다를 수 있습니다. 예를 들어 기본 reverse_view 범위에 random_access_iterator.bidirectional_iterator

  • 요소 형식: 뷰의 반복기가 반환하는 요소의 형식입니다.

  • 크기 조정: 뷰가 참조하는 요소 수를 반환할 수 있는지 여부입니다. 모든 보기가 가능하지는 않습니다.

  • 공통 범위: 뷰가 common_range뷰인지 여부를 지정합니다. 즉, 시작 반복기와 sentinel 형식이 동일합니다. 공통 범위는 반복기 쌍에서 작동하는 사전 범위 코드에 유용합니다. 예를 들어 시퀀스 컨테이너에 대한 반복기 쌍 생성자(예: vector(ranges::begin(x), ranges::end(x)).

  • 대여된 범위: 보기가 빌린 범위인지 여부를 지정합니다. borrowed_range<T>는 제거된 후 T 반복기를 T 사용할 수 있다는 의미입니다.

    컨테이너를 삭제하면 요소가 해제되고 반복기가 무효화되기 때문에 표준 컨테이너는 빌린 범위가 아닙니다. 이 경우 반복기는 파괴 후 "매달려"남아 있다고 말합니다.

    예를 들어 std::ranges::find() 일반적으로 범위 인수에서 찾은 요소에 대한 반복기를 반환합니다. 범위 인수가 임시(rvalue) 컨테이너인 경우 반환된 반복기를 저장하고 나중에 "현수"이므로 사용하는 것은 실수입니다.

    반복기(또는 하위 범위)를 반환하는 범위 알고리즘은 인수가 lvalue(임시가 아닌) 또는 대여된 범위인 경우에만 이 작업을 수행합니다. 그렇지 않으면 반복기처럼 사용하려고 하면 무엇이 잘못되었는지에 대한 오류 메시지의 힌트를 제공하는 개체를 반환 std::dangling 합니다.

  • const 반복 가능 여부: 뷰의 인스턴스를 const 반복할 수 있는지 여부를 나타냅니다. 모든 const 보기를 반복할 수 있는 것은 아닙니다. 보기를 반복할 수 없는 경우 뷰를 반복 for (const auto& element : as_const(theView)) 하거나 뷰에 대한 참조를 사용한 const 다음 반복을 시도하는 함수에 전달할 수 없습니다const.

범위 반복기 계층 구조

각 보기 클래스 항목의 특성 섹션에서 기본 범위뷰 반복기 범주의 반복기 범주 는 범위/뷰에서 지원하는 반복기의 종류를 나타냅니다. C++20 개념으로 식별되는 범위 반복기에는 6가지 범주가 있습니다. 기능 순서가 증가하는 범위 반복기의 계층 구조는 다음과 같습니다.

범위 반복기 개념 설명
output_range 쓰기 전용으로, 앞으로만 이동합니다. 단일 패스입니다.
input_range 읽기 전용으로, 앞으로만 이동합니다. 단일 패스입니다.
forward_range 앞으로만 이동합니다. 다중 패스.
bidirectional_range 앞뒤로 이동할 수 있습니다. 다중 패스.
random_access_range 인덱스로 컬렉션에 액세스할 수 있습니다. 다중 패스.
contiguous_range 인덱스로 컬렉션에 액세스할 수 있으며 요소는 메모리에 연속적으로 저장됩니다.

일반적으로 반복기에는 테이블 앞에 오는 반복기의 기능이 있습니다. 예를 들어 bidirectional_range 해당 기능은 있지만 그 반대의 forward_range경우도 마찬가지입니다. 단input_range, 에 쓸 input_range수 없기 때문에 기능이 output_range 없습니다.

"필요 input_range 또는 그 이상" 문은 뷰가 모두 다음과 같이 input_range가능하기 때문에 뷰를 , bidirectional_rangeforward_range, random_access_range또는 contiguous_range 반복기와 함께 input_range사용할 수 있음을 의미합니다.

범위 반복기 계층 구조는 반복기 계층 구조와 직접 관련이 있습니다. 자세한 내용은 반복기 개념을 참조 하세요.

참고 항목

<ranges>
범위 어댑터