反覆運算器概念
概念是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
。
在下表中,「多階段」是指反覆運算器是否可以多次重新流覽相同的元素。 例如, vector::iterator
是多重傳遞反覆運算器,因為您可以建立反覆運算器的複本、讀取集合中的元素,然後將反覆運算器還原至複本中的值,然後再次重新流覽相同的元素。 如果反覆運算器是單一傳遞,您就只能流覽集合中的元素一次。
在下表中,「範例類型」是指滿足概念的集合/反覆運算器。
反覆運算器概念 | 描述 | 方向 | 讀取/寫入 | 多階段 | 範例類型 |
---|---|---|---|---|---|
input_or_output_iterator C++20 |
反覆運算器概念分類的基礎。 | 轉寄 | 讀取/寫入 | 否 | istream_iterator , ostream_iterator |
output_iterator C++20 |
指定您可以寫入的反覆運算器。 | 轉寄 | 寫入 | 否 | ostream , inserter |
input_iterator C++20 |
指定您可以從一次讀取的反覆運算器。 | 轉寄 | 讀取 | 否 | istream , istreambuf_iterator |
forward_iterator C++20 |
指定可多次讀取(且可能寫入)的反覆運算器。 | 轉寄 | 讀取/寫入 | 是 | vector , list |
bidirectional_iterator C++20 |
指定您可以向前和向後讀取和寫入的反覆運算器。 | 向前或向後 | 讀取/寫入 | 是 | list 、set 、multiset 、map 和 multimap 。 |
random_access_iterator C++20 |
指定您可以依索引讀取和寫入的反覆運算器。 | 向前或向後 | 讀取/寫入 | 是 | vector 、 、 array deque |
contiguous_iterator C++20 |
指定反覆運算器,其元素在記憶體中循序、大小相同,而且可以使用指標算術來存取。 | 向前或向後 | 讀取/寫入 | 是 | array 、 vector string 。 |
其他反覆運算器概念包括:
反覆運算器概念 | 描述 |
---|---|
sentinel_for C++20 |
指定類型是反覆運算器類型的sentinel。 |
sized_sentinel_for C++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
、、multimap
map
、 vector
和 list
。
範例: 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
些範例包括 array
、 vector
與 string
。
範例: 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_multiset
unordered_set
、 unordered_map
和 unordered_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_iterator
、 forward_iterator
和 bidirectional_iterator
的功能input_iterator
。
一 random_access_iterator
些範例包括 vector
、 array
與 deque
。
範例: 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
要測試的類型,以查看其是否為的 I
sentinel。
備註
sentinel 是一種類型,可以與反覆運算器進行比較,以判斷反覆運算器是否已到達結尾。 這個概念會判斷類型是否為其中input_or_output_iterator
一種類型的 sentinel,其中包括 input_iterator
、output_iterator
、、forward_iterator
bidirectional_iterator
、 random_access_iterator
和 contiguous_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
}