다음을 통해 공유


반복기 개념

개념은 컴파일 시간에 템플릿 매개 변수를 제한하는 C++20 언어 기능입니다. 잘못된 템플릿 인스턴스화를 방지하고, 읽을 수 있는 형식으로 템플릿 인수 요구 사항을 지정하고, 더 간결한 템플릿 관련 컴파일러 오류를 제공하는 데 도움이 됩니다.

다음 예제에서는 나누기를 지원하지 않는 형식으로 템플릿을 인스턴스화하지 않도록 하는 개념을 정의합니다.

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

// Definition of dividable concept which requires 
// that arguments a & b of type T support division
template <typename T>
concept dividable = requires (T a, T b)
{
    a / b;
};

// Apply the concept to a template.
// The template will only be instantiated if argument T supports division.
// This prevents the template from being instantiated with types that don't support division.
// This could have been applied to the parameter of a template function, but because
// most of the concepts in the <ranges> library are applied to classes, this form is demonstrated.
template <class T> requires dividable<T>
class DivideEmUp
{
public:
    T Divide(T x, T y)
    {
        return x / y;
    }
};

int main()
{
    DivideEmUp<int> dividerOfInts;
    std::cout << dividerOfInts.Divide(6, 3); // outputs 2
    // The following line will not compile because the template can't be instantiated 
    // with char* because char* can be divided
    DivideEmUp<char*> dividerOfCharPtrs; // compiler error: cannot deduce template arguments 
}

컴파일러 스위치 /diagnostics:caret 를 Visual Studio 2022 버전 17.4 미리 보기 4 이상으로 전달하면 개념 dividable<char*> 이 false로 평가되는 오류는 실패한 식 요구 사항을 (a / b) 직접 가리킵니다.

반복기 개념은 네임스페이 std 스에 정의되며 헤더 파일에 선언됩니다 <iterator> . 범위 어댑터, 등의 선언에 사용됩니다.

반복기에는 6가지 범주가 있습니다. 범위 개념에 나열된 범위 범주와 직접 관련이 있습니다.

다음 반복기 개념은 기능 증가 순서대로 나열됩니다. input_or_output_iterator 는 기능 계층 구조의 하위 끝에 있으며 contiguous_iterator 하이 엔드에 있습니다. 계층 구조에서 더 높은 반복기는 일반적으로 낮은 반복기 대신 사용할 수 있지만 그 반대의 경우도 마찬가지입니다. 예를 들어 random_access_iterator 반복기를 대신 forward_iterator사용할 수 있지만 다른 방법으로는 사용할 수 없습니다. 예외는 input_iterator쓸 수 없기 때문에 대신 output_iterator 사용할 수 없는 것입니다.

Diagram of the iterator hierarchy. input_or_output_iterator is the base. input_iterator and output_iterator are shown as refining input_or_output_iterator. forward_iterator is next and refines both input_iterator and output_iterator. bidirectional_iterator refines forward_iterator. random_access_iterator refines bidirectional_iterator. Finally, contiguous_iterator refines random_access_iterator

다음 표에서 "다중 패스"는 반복기가 동일한 요소를 두 번 이상 다시 방문할 수 있는지 여부를 나타냅니다. 예를 들어 vector::iterator 반복기의 복사본을 만들고, 컬렉션의 요소를 읽은 다음, 반복기를 복사본의 값으로 복원하고, 동일한 요소를 다시 다시 방문할 수 있기 때문에 다중 전달 반복기가 있습니다. 반복기가 단일 패스인 경우 컬렉션의 요소를 한 번만 방문할 수 있습니다.

다음 표에서 "예제 형식"은 개념을 충족하는 컬렉션/반복기를 나타냅니다.

반복기 개념 설명 Direction 읽기/쓰기 다중 패스 예제 형식
input_or_output_iteratorC++20 반복기 개념 분류의 기초입니다. 앞으로 읽기/쓰기 아니요 istream_iterator, ostream_iterator
output_iteratorC++20 쓸 수 있는 반복기를 지정합니다. 앞으로 쓰기 아니요 ostream, inserter
input_iteratorC++20 한 번 읽을 수 있는 반복기를 지정합니다. 앞으로 Read 아니요 istream, istreambuf_iterator
forward_iteratorC++20 여러 번 읽고 쓸 수 있는 반복기를 지정합니다. 앞으로 읽기/쓰기 vector, list
bidirectional_iteratorC++20 앞뒤로 읽고 쓸 수 있는 반복기를 지정합니다. 앞으로 또는 뒤로 읽기/쓰기 list, set, multiset, mapmultimap.
random_access_iteratorC++20 인덱스로 읽고 쓸 수 있는 반복기를 지정합니다. 앞으로 또는 뒤로 읽기/쓰기 vector, array, deque
contiguous_iteratorC++20 요소가 메모리에서 순차적이고 크기가 같으며 포인터 산술 연산을 사용하여 액세스할 수 있는 반복기를 지정합니다. 앞으로 또는 뒤로 읽기/쓰기 array, vectorstring.

다른 반복기 개념은 다음과 같습니다.

반복기 개념 설명
sentinel_forC++20 형식이 반복기 형식의 sentinel임을 지정합니다.
sized_sentinel_forC++20 반복기와 해당 sentinel을 빼서(사용 -) 일정한 시간에 차이를 찾을 수 있도록 지정합니다.

bidirectional_iterator

A bidirectional_iterator 는 앞뒤로 읽고 쓰는 것을 지원합니다.

template<class I>
concept bidirectional_iterator =
    forward_iterator<I> &&
    derived_from<ITER_CONCEPT(I), bidirectional_iterator_tag> &&
    requires(I i) {
        {--i} -> same_as<I&>;
        {i--} -> same_as<I>;
};

매개 변수

I
테스트할 반복기가 .인지 확인 bidirectional_iterator합니다.

설명

A bidirectional_iterator 에는 A의 forward_iterator기능이 있지만 뒤로 반복할 수도 있습니다.

와 함께 bidirectional_iterator 사용할 수 있는 컨테이너의 몇 가지 예는 set, multiset, mapmultimap, vectorlist.

예: bidirectional_iterator

다음 예제에서는 개념을 사용하여 bidirectional_iterator 다음이 있음을 vector<int> 표시합니다.bidirectional_iterator

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

int main()
{
    std::cout << std::boolalpha << std::bidirectional_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::contiguous_iterator<decltype(v)::iterator>; // outputs true
}

contiguous_iterator

요소가 메모리에서 순차적이고 크기가 같으며 포인터 산술 연산을 사용하여 액세스할 수 있는 반복기를 지정합니다.

template<class I>
    concept contiguous_iterator =
        random_access_iterator<I> &&
        derived_from<ITER_CONCEPT(I), contiguous_iterator_tag> &&
        is_lvalue_reference_v<iter_reference_t<I>> &&
        same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> &&
        requires(const I& i) {
            { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>;
        };

매개 변수

I
테스트할 형식이 .인지 확인합니다 contiguous_iterator.

설명

요소가 메모리에 순차적으로 배치되고 크기가 같기 때문에 포인터 산술 연산을 통해 A contiguous_iterator 에 액세스할 수 있습니다. 의 몇 가지 예는 contiguous_iteratorarray, vectorstring.

예: contiguous_iterator

다음 예제에서는 개념을 사용하여 contiguous_iterator 다음 vector<int> 이 있음을 보여줍니다.contiguous_iterator

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

int main()
{
    // Show that vector<int> has a contiguous_iterator
    std::cout << std::boolalpha << std::contiguous_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"
    
    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::contiguous_iterator<decltype(v)::iterator>; // outputs true
}

forward_iterator

의 기능이 input_iterator 있습니다 output_iterator. 컬렉션을 여러 번 반복할 수 있습니다.

template<class I>
    concept forward_iterator =
        input_iterator<I> &&
        derived_from<ITER_CONCEPT(I), forward_iterator_tag> &&
        incrementable<I> &&
        sentinel_for<I, I>;

매개 변수

I
테스트할 반복기가 .인지 확인 forward_iterator합니다.

설명

A는 forward_iterator 앞으로만 이동할 수 있습니다.

와 함께 forward_iterator 사용할 수 있는 컨테이너의 몇 가지 예는 vector, list, unordered_setunordered_multiset, unordered_mapunordered_multimap.

예: forward_iterator

다음 예제에서는 개념을 사용하여 forward_iterator 다음 vector<int> 이 있음을 보여줍니다.forward_iterator

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

int main()
{
    // Show that vector has a forward_iterator
    std::cout << std::boolalpha << std::forward_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::forward_iterator<decltype(v)::iterator>; // outputs true
}

input_iterator

input_iterator 번 이상 읽을 수 있는 반복기입니다.

template<class I>
concept input_iterator =
    input_or_output_iterator<I> &&
    indirectly_readable<I> &&
    requires { typename ITER_CONCEPT(I); } &&
    derived_from<ITER_CONCEPT(I), input_iterator_tag>;

매개 변수

I
테스트 input_iterator할 형식입니다.

설명

input_iterator 두 번 이상 호출 begin() 하면 정의되지 않은 동작이 발생합니다. 모델 input_iterator 만 다중 패스가 아닌 형식입니다. 예를 들어 표준 입력(cin)에서 읽는 것이 좋습니다. 이 경우 현재 요소를 한 번만 읽을 수 있으며 이미 읽은 문자를 다시 읽을 수 없습니다. 뒤로 input_iterator 만 읽지 않고 앞으로 읽습니다.

예: input_iterator

다음 예제에서는 개념을 사용하여 input_iterator 다음이 있음을 istream_iterator 보여줍니다.input_iterator

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

int main()
{
    // Show that a istream_iterator has an input_iterator
    std::cout << std::boolalpha << std::input_iterator<std::istream_iterator<int>>; // outputs true
}

input_or_output_iterator

반복 input_or_output_iterator 기 개념 분류의 기초입니다. 반복기를 역참조 및 증가시키는 것을 지원합니다. 모든 반복기 모델 input_or_output_iterator.

template<class I>
concept input_or_output_iterator =
    requires(I i) {
        { *i } -> can-reference;
    } &&
    weakly_incrementable<I>;

매개 변수

I
테스트 input_or_output_iterator할 형식입니다.

설명

이 개념은 can-reference 형식 I 이 참조, 포인터 또는 참조로 암시적으로 변환될 수 있는 형식임을 의미합니다.

예: input_or_output_iterator

다음 예제에서는 개념을 사용하여 input_or_output_iterator 다음이 있음을 vector<int> 표시합니다.input_or_output_iterator

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

int main()
{
    // Show that a vector has an input_or_output_iterator
    std::cout << std::boolalpha << std::input_or_output_iterator<std::vector<int>::iterator> << '\n'; // outputs true

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::input_or_output_iterator<decltype(v)::iterator>; // outputs true
}

output_iterator

작성 output_iterator 할 수 있는 반복기입니다.

template<class I, class T>
concept output_iterator =
    input_or_output_iterator<I> &&
    indirectly_writable<I, T> &&
    requires(I i, T&& t) {
        *i++ = std::forward<T>(t);
    };

매개 변수

I
테스트 output_iterator할 형식입니다.

T
쓸 값의 형식입니다.

설명

단일 output_iterator 패스입니다. 즉, 동일한 요소에 한 번만 쓸 수 있습니다.

예: output_iterator

다음 예제에서는 개념을 사용하여 output_iterator 다음이 있음을 vector<int> 표시합니다.output_iterator

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

int main()
{
    // Show that vector<int> has an output_iterator
    std::cout << std::boolalpha << std::output_iterator<std::vector<int>::iterator, int> << "\n"; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2,3,4,5};
    std::cout << std::boolalpha << std::output_iterator<decltype(v)::iterator, int>; // outputs true
}

random_access_iterator

A는 random_access_iterator 인덱스로 읽거나 쓸 수 있습니다.

template<class I>
concept random_access_iterator =
    bidirectional_iterator<I> &&
    derived_from<ITER_CONCEPT(I), random_access_iterator_tag> &&
    totally_ordered<I> &&
    sized_sentinel_for<I, I> &&
    requires(I i, const I j, const iter_difference_t<I> n) {
        { i += n } -> same_as<I&>;
        { j + n } -> same_as<I>;
        { n + j } -> same_as<I>;
        { i -= n } -> same_as<I&>;
        { j - n } -> same_as<I>;
        { j[n] } -> same_as<iter_reference_t<I>>;
    };

매개 변수

I
테스트할 형식이 .인지 확인합니다 random_access_iterator.

설명

A random_access_iterator 에는 , output_iterator, forward_iteratorbidirectional_iterator.input_iterator

의 몇 가지 예는 random_access_iteratorvector, arraydeque.

예: random_access_iterator

다음 예제에서는 a에 vector<int> 다음이 있음을 보여줍니다.random_access_iterator

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

int main()
{
    // Show that vector<int> has a random_access_iterator
    std::cout << std::boolalpha << std::random_access_iterator<std::vector<int>::iterator> << '\n'; // outputs "true"

    // another way to test
    std::vector<int> v = {0,1,2};
    std::cout << std::boolalpha << std::random_access_iterator<decltype(v)::iterator>; // outputs true
}    

sentinel_for

형식이 반복기의 sentinel임을 지정합니다.

template<class S, class I>
concept sentinel_for =
    semiregular<S> &&
    input_or_output_iterator<I> &&
    weakly-equality-comparable-with <S, I>;

매개 변수

I
반복기 형식입니다.

S
에 대한 Isentinel인지 확인하기 위해 테스트할 형식입니다.

설명

sentinel은 반복기가 끝에 도달했는지 확인하기 위해 반복기와 비교할 수 있는 형식입니다. 이 개념은 형식이 , output_iterator,forward_iteratorbidirectional_iteratorrandom_access_iterator, 및 contiguous_iterator를 포함하는 input_iterator형식 중 input_or_output_iterator 하나에 대한 sentinel인지 여부를 결정합니다.

예: sentinel_for

다음 예제에서는 개념을 사용하여 sentinel_for 다음의 센티넬임을 vector<int>::iterator 표시합니다 vector<int>.

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

int main()
{
    std::vector<int> v = {0, 1, 2};
    std::vector<int>::iterator i = v.begin();
    // show that vector<int>::iterator is a sentinel for vector<int>
    std::cout << std::boolalpha << std::sentinel_for<std::vector<int>::iterator, decltype(i)>; // outputs true
}    

sized_sentinel_for

반복기와 해당 sentinel을 빼 - 서 일정한 시간에 차이를 찾을 수 있는지 테스트합니다.

template<class S, class I>
concept sized_sentinel_for =
    sentinel_for<S, I> &&
    !disable_sized_sentinel_for<remove_cv_t<S>, remove_cv_t<I>> &&
    requires(const I& i, const S& s) {
        {s - i} -> same_as<iter_difference_t<I>>;
        {i - s} -> same_as<iter_difference_t<I>>;
    };

매개 변수

I
반복기 형식입니다.

S
테스트할 sentinel 형식입니다.

설명

예: sized_sentinel_for

다음 예제에서는 이 개념을 사용하여 sized_sentinel_for 일정한 시간에 벡터 반복기에서 a의 sentinel vector<int> 을 뺄 수 있는지 확인합니다.

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

int main()
{
    std::vector<int> v = { 1, 2, 3 };
    std::vector<int>::iterator i = v.begin();
    std::vector<int>::iterator end = v.end();
    // use the sized_sentinel_for concept to verify that i can be subtracted from end in constant time
    std::cout << std::boolalpha << std::sized_sentinel_for<decltype(end), decltype(i)> << "\n"; // outputs true
    std::cout << end - i; // outputs 3
}    

참고 항목

범위 개념
범위 어댑터
클래스 보기