共用方式為


反覆運算器概念

概念是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版 Preview 4 或更新版本時,評估為 false 的概念 dividable<char*> 錯誤會直接指向失敗的表達式需求 (a / b)

反覆運算器概念定義於 std 命名空間中,並在頭檔中宣告 <iterator> 。 它們用於範圍配接器檢視表等的宣告中。

反覆運算器有六種類別。 它們與範圍概念所列的範圍類別直接相關。

下列反覆運算器概念會依增加功能的順序列出。 input_or_output_iterator 位於功能階層的低端,且 contiguous_iterator 位於高端。 階層中的反覆運算器通常可以用來取代較低層級的反覆運算器,但反之亦然。 例如, random_access_iterator 反覆運算器可用來取代 forward_iterator,但不能以另一種方式來取代 。 例外狀況是 input_iterator,因為無法寫入,所以無法取代 output_iterator

反覆運算器階層的圖表。input_or_output_iterator是基底。input_iterator和output_iterator會顯示為精簡input_or_output_iterator。forward_iterator是下一個,並精簡input_iterator和output_iterator。bidirectional_iterator精簡forward_iterator。random_access_iterator精簡bidirectional_iterator。最後,contiguous_iterator精簡random_access_iterator

在下表中,「多階段」是指反覆運算器是否可以多次重新流覽相同的元素。 例如, vector::iterator 是多重傳遞反覆運算器,因為您可以建立反覆運算器的複本、讀取集合中的元素,然後將反覆運算器還原至複本中的值,然後再次重新流覽相同的元素。 如果反覆運算器是單一傳遞,您就只能流覽集合中的元素一次。

在下表中,「範例類型」是指滿足概念的集合/反覆運算器。

反覆運算器概念 描述 方向 讀取/寫入 多階段 範例類型
input_or_output_iteratorC++20 反覆運算器概念分類的基礎。 轉寄 讀取/寫入 istream_iterator, ostream_iterator
output_iteratorC++20 指定您可以寫入的反覆運算器。 轉寄 寫入 ostream, inserter
input_iteratorC++20 指定您可以從一次讀取的反覆運算器。 轉寄 讀取 istream, istreambuf_iterator
forward_iteratorC++20 指定可多次讀取(且可能寫入)的反覆運算器。 轉寄 讀取/寫入 vector, list
bidirectional_iteratorC++20 指定您可以向前和向後讀取和寫入的反覆運算器。 向前或向後 讀取/寫入 listsetmultisetmapmultimap
random_access_iteratorC++20 指定您可以依索引讀取和寫入的反覆運算器。 向前或向後 讀取/寫入 vector、 、 arraydeque
contiguous_iteratorC++20 指定反覆運算器,其元素在記憶體中循序、大小相同,而且可以使用指標算術來存取。 向前或向後 讀取/寫入 arrayvector string

其他反覆運算器概念包括:

反覆運算器概念 描述
sentinel_forC++20 指定類型是反覆運算器類型的sentinel。
sized_sentinel_forC++20 指定反覆運算器及其 sentinel 可以減去 (使用 -) 來尋找常數時間的差異。

bidirectional_iterator

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

備註

bidirectional_iterator具有的功能forward_iterator,但也可以往後反覆運算。

可以搭配 bidirectional_iterator 使用的容器範例包括set、、multiset、、multimapmapvectorlist

範例: 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

備註

contiguous_iterator指標算術可以存取 ,因為元素會循序配置在記憶體中,而且大小相同。 一 contiguous_iterator 些範例包括 arrayvectorstring

範例: 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

具有和output_iterator的功能input_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

備註

forward_iterator只能向前移動。

可以搭配 forward_iterator 使用的容器範例包括vector、、list、、unordered_multisetunordered_setunordered_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

備註

呼叫begin()input_iterator一次以上會導致未定義的行為。 只有模型 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

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

備註

random_access_iterator具有、output_iteratorforward_iteratorbidirectional_iterator的功能input_iterator

random_access_iterator 些範例包括 vectorarraydeque

範例: random_access_iterator

下列範例顯示 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 是一種類型,可以與反覆運算器進行比較,以判斷反覆運算器是否已到達結尾。 這個概念會判斷類型是否為其中input_or_output_iterator一種類型的 sentinel,其中包括 input_iteratoroutput_iterator、、forward_iteratorbidirectional_iteratorrandom_access_iteratorcontiguous_iterator

範例: sentinel_for

下列範例會 sentinel_for 使用 概念來顯示 vector<int>::iterator 的 sentinel 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 使用 概念來確認 的 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
}    

另請參閱

範圍概念
範圍配接器
檢視類別