Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Konsep adalah fitur bahasa C++20 yang membatasi parameter templat pada waktu kompilasi. Ini membantu mencegah instansiasi templat yang salah, menentukan persyaratan argumen templat dalam bentuk yang dapat dibaca, dan memberikan kesalahan kompilator terkait templat yang lebih ringkas.
Pertimbangkan contoh berikut, yang menentukan konsep untuk mencegah pembuatan instans templat dengan jenis yang tidak mendukung pembagian:
// 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
}
Saat Anda meneruskan sakelar /diagnostics:caret kompilator ke Visual Studio 2022 versi 17.4 pratinjau 4 atau yang lebih baru, kesalahan yang dievaluasi konsep dividable<char*> ke false akan mengarah langsung ke persyaratan (a / b) ekspresi yang gagal.
Konsep iterator didefinisikan dalam std namespace layanan, dan dideklarasikan dalam <iterator> file header. Mereka digunakan dalam deklarasi adaptor rentang, tampilan, dan sebagainya.
Ada enam kategori iterator. Mereka terkait langsung dengan kategori rentang yang tercantum di bawah Konsep rentang.
Konsep iterator berikut tercantum dalam urutan peningkatan kemampuan.
input_or_output_iterator berada di ujung rendah hierarki kemampuan, dan contiguous_iterator berada di ujung atas. Iterator yang lebih tinggi dalam hierarki umumnya dapat digunakan sebagai pengganti yang lebih rendah, tetapi tidak sebaliknya. Misalnya, iterator random_access_iterator dapat digunakan sebagai pengganti forward_iterator, tetapi bukan sebaliknya. Pengecualiannya adalah input_iterator, yang tidak dapat digunakan karena output_iterator tidak dapat menulis.
Dalam tabel berikut, "Multi-pass" mengacu pada apakah iterator dapat mengunjungi kembali elemen yang sama lebih dari sekali. Misalnya, vector::iterator adalah iterator multi-pass karena Anda dapat membuat salinan iterator, membaca elemen dalam koleksi, lalu memulihkan iterator ke nilai dalam salinan, dan mengunjungi kembali elemen yang sama lagi. Jika iterator adalah single-pass, Anda hanya dapat mengunjungi elemen dalam koleksi sekali.
Dalam tabel berikut, "Jenis contoh" mengacu pada koleksi/iterator yang memenuhi konsep.
| Konsep iterator | Deskripsi | Petunjuk | Baca/tulis | Multi-pass | Contoh jenis |
|---|---|---|---|---|---|
input_or_output_iterator
C++20 |
Dasar taksonomi konsep iterator. | Selanjutnya | Baca/tulis | Tidak |
istream_iterator, ostream_iterator |
output_iterator
C++20 |
Menentukan iterator yang dapat Anda tulis. | Selanjutnya | Menulis | Tidak |
ostream, inserter |
input_iterator
C++20 |
Menentukan iterator yang dapat Anda baca sekali. | Selanjutnya | Bacalah | Tidak |
istream, istreambuf_iterator |
forward_iterator
C++20 |
Menentukan iterator yang dapat membaca (dan mungkin menulis) beberapa kali. | Selanjutnya | Baca/tulis | Ya |
vector, list |
bidirectional_iterator
C++20 |
Menentukan iterator yang dapat Anda baca dan tulis teruskan dan mundur. | Maju atau mundur | Baca/tulis | Ya |
list, , setmultiset, map, dan multimap. |
random_access_iterator
C++20 |
Menentukan iterator yang dapat Anda baca dan tulis menurut indeks. | Maju atau mundur | Baca/tulis | Ya |
vector, , arraydeque |
contiguous_iterator
C++20 |
Menentukan iterator yang elemennya berurutan dalam memori, berukuran sama, dan dapat diakses menggunakan aritmatika penunjuk. | Maju atau mundur | Baca/tulis | Ya |
array, , vector. string |
Konsep iterator lainnya meliputi:
| Konsep iterator | Deskripsi |
|---|---|
sentinel_for
C++20 |
Menentukan bahwa jenis adalah sentinel untuk jenis iterator. |
sized_sentinel_for
C++20 |
Menentukan bahwa iterator dan sentinelnya dapat dikurangi (menggunakan -) untuk menemukan perbedaannya dalam waktu konstan. |
bidirectional_iterator
Mendukung bidirectional_iterator pembacaan dan penulisan maju dan mundur.
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>;
};
Parameter
I
Iterator untuk menguji untuk melihat apakah itu adalah bidirectional_iterator.
Keterangan
A bidirectional_iterator memiliki kemampuan forward_iterator, tetapi juga dapat melakukan iterasi mundur.
Beberapa contoh kontainer yang dapat digunakan dengan bidirectional_iterator adalah , , set, multisetmap, multimap, dan vectorlist.
Contoh: bidirectional_iterator
Contoh berikut menggunakan bidirectional_iterator konsep untuk menunjukkan yang vector<int> memiliki 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
Menentukan iterator yang elemennya berurutan dalam memori, berukuran sama, dan dapat diakses menggunakan aritmatika penunjuk.
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>>>;
};
Parameter
I
Jenis yang akan diuji untuk melihat apakah itu adalah contiguous_iterator.
Keterangan
contiguous_iterator Dapat diakses oleh aritmatika pointer karena elemen ditata secara berurutan dalam memori dan berukuran sama. Beberapa contoh contiguous_iterator adalah array, , vectordan string.
Contoh: contiguous_iterator
Contoh berikut menggunakan contiguous_iterator konsep untuk menunjukkan bahwa memiliki 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
Memiliki kemampuan dan input_iteratoroutput_iterator. Mendukung iterasi selama koleksi beberapa kali.
template<class I>
concept forward_iterator =
input_iterator<I> &&
derived_from<ITER_CONCEPT(I), forward_iterator_tag> &&
incrementable<I> &&
sentinel_for<I, I>;
Parameter
I
Iterator untuk menguji untuk melihat apakah itu adalah forward_iterator.
Keterangan
A forward_iterator hanya dapat bergerak maju.
Beberapa contoh kontainer yang dapat digunakan dengan forward_iterator adalah , , vector, listunordered_set, unordered_multiset, dan unordered_mapunordered_multimap.
Contoh: forward_iterator
Contoh berikut menggunakan forward_iterator konsep untuk menunjukkan bahwa memiliki 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 adalah iterator yang dapat Anda baca dari setidaknya sekali.
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>;
Parameter
I
Jenis yang akan diuji untuk melihat apakah itu adalah input_iterator.
Keterangan
Memanggil begin() pada input_iterator lebih dari sekali menghasilkan perilaku yang tidak ditentukan. Jenis yang hanya model input_iterator tidak multi-pass. Pertimbangkan untuk membaca dari input standar (cin) misalnya. Dalam hal ini, Anda hanya dapat membaca elemen saat ini sekali dan Anda tidak dapat membaca ulang karakter yang telah Anda baca. Satu-satunya input_iterator bacaan ke depan, bukan mundur.
Contoh: input_iterator
Contoh berikut menggunakan input_iterator konsep untuk menunjukkan bahwa memiliki istream_iteratorinput_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
Adalah input_or_output_iterator dasar dari taksonomi konsep iterator. Ini mendukung dereferensi dan inkrementasi iterator. Setiap model input_or_output_iteratoriterator .
template<class I>
concept input_or_output_iterator =
requires(I i) {
{ *i } -> can-reference;
} &&
weakly_incrementable<I>;
Parameter
I
Jenis yang akan diuji untuk melihat apakah itu adalah input_or_output_iterator.
Keterangan
Konsepnya can-reference berarti bahwa jenis I tersebut adalah referensi, penunjuk, atau jenis yang dapat dikonversi secara implisit menjadi referensi.
Contoh: input_or_output_iterator
Contoh berikut menggunakan input_or_output_iterator konsep untuk menunjukkan yang vector<int> memiliki 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 Adalah iterator yang dapat Anda tulis.
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);
};
Parameter
I
Jenis yang akan diuji untuk melihat apakah itu adalah output_iterator.
T
Jenis nilai yang akan ditulis.
Keterangan
Sebuah output_iterator adalah single pass. Artinya, ia hanya dapat menulis ke elemen yang sama sekali.
Contoh: output_iterator
Contoh berikut menggunakan output_iterator konsep untuk menunjukkan yang vector<int> memiliki 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
Dapat random_access_iterator membaca atau menulis berdasarkan indeks.
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>>;
};
Parameter
I
Jenis yang akan diuji untuk melihat apakah itu adalah random_access_iterator.
Keterangan
A random_access_iterator memiliki kemampuan input_iterator, , output_iterator, forward_iteratordan bidirectional_iterator.
Beberapa contoh random_access_iterator adalah vector, , arraydan deque.
Contoh: random_access_iterator
Contoh berikut menunjukkan bahwa memiliki 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
Menentukan bahwa jenis adalah sentinel untuk iterator.
template<class S, class I>
concept sentinel_for =
semiregular<S> &&
input_or_output_iterator<I> &&
weakly-equality-comparable-with <S, I>;
Parameter
I
Jenis iterator.
S
Jenis yang akan diuji untuk melihat apakah itu sentinel untuk I.
Keterangan
Sentinel adalah jenis yang dapat dibandingkan dengan iterator untuk menentukan apakah iterator telah mencapai akhir. Konsep ini menentukan apakah jenis adalah sentinel untuk salah satu jenisinput_or_output_iterator, yang mencakup input_iterator, , output_iterator, forward_iteratorbidirectional_iterator, random_access_iterator, dan contiguous_iterator.
Contoh: sentinel_for
Contoh berikut menggunakan sentinel_for konsep untuk menunjukkan bahwa vector<int>::iterator adalah sentinel untuk 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
Uji bahwa iterator dan sentinelnya dapat dikurangi menggunakan - untuk menemukan perbedaannya, dalam waktu konstan.
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>>;
};
Parameter
I
Jenis iterator.
S
Jenis sentinel untuk diuji.
Contoh: sized_sentinel_for
Contoh berikut menggunakan sized_sentinel_for konsep untuk memverifikasi bahwa sentinel untuk vector<int> dapat dikurangi dari iterator vektor dalam waktu konstan:
// 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
}