Standar telah diubah sejak pertanyaan (dan sebagian besar jawaban) diposting dalam resolusi laporan cacat ini .
Cara membuat for(:)
loop bekerja pada tipe Anda X
sekarang adalah salah satu dari dua cara:
Buat anggota X::begin()
dan X::end()
kembalikan sesuatu yang bertindak seperti iterator
Buat fungsi gratis begin(X&)
dan end(X&)
yang mengembalikan sesuatu yang bertindak seperti iterator, di namespace yang sama dengan tipe Anda X
.¹
Dan serupa untuk const
variasi. Ini akan bekerja pada kompiler yang mengimplementasikan perubahan laporan cacat, dan kompiler yang tidak.
Objek yang dikembalikan tidak harus benar-benar menjadi iterator. The for(:)
Loop, tidak seperti sebagian besar C ++ standar, yang ditentukan untuk memperluas untuk sesuatu yang setara dengan :
for( range_declaration : range_expression )
menjadi:
{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
di mana variabel yang dimulai dengan __
hanya untuk eksposisi, dan begin_expr
dan end_expr
adalah sihir yang memanggil begin
/ end
.²
Persyaratan pada nilai pengembalian awal / akhir sederhana: Anda harus kelebihan pre- ++
, memastikan ekspresi inisialisasi valid, biner !=
yang dapat digunakan dalam konteks boolean, unary *
yang mengembalikan sesuatu yang dapat Anda tetapkan-inisialisasi range_declaration
dengan, dan mengekspos publik destruktor.
Melakukannya dengan cara yang tidak kompatibel dengan iterator mungkin merupakan ide yang buruk, karena iterasi C ++ di masa depan mungkin relatif lebih berani tentang memecahkan kode Anda jika Anda melakukannya.
Sebagai tambahan, ada kemungkinan wajar bahwa revisi standar di masa depan akan memungkinkan end_expr
untuk mengembalikan jenis yang berbeda dari begin_expr
. Ini berguna karena memungkinkan evaluasi "lazy-end" (seperti mendeteksi null-termination) yang mudah dioptimalkan agar seefisien loop C tulisan tangan, dan keuntungan serupa lainnya.
¹ Perhatikan bahwa for(:)
loop menyimpan sementara apa pun dalam auto&&
variabel, dan memberikannya kepada Anda sebagai nilai. Anda tidak dapat mendeteksi jika Anda mengulanginya sementara (atau nilai lainnya); kelebihan seperti itu tidak akan dipanggil dengan for(:)
loop. Lihat [stmt.ranged] 1.2-1.3 dari n4527.
² Baik panggil metode begin
/ end
, atau pencarian fungsi bebas ADL saja begin
/ end
, atau sulap untuk dukungan larik gaya-C. Catatan yang std::begin
tidak dipanggil kecuali range_expression
mengembalikan objek bertipe namespace std
atau bergantung pada yang sama.
Di c ++ 17 rentang-untuk ekspresi telah diperbarui
{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
dengan jenis __begin
dan __end
telah dipisahkan.
Ini memungkinkan iterator akhir untuk tidak menjadi tipe yang sama seperti mulai. Jenis iterator akhir Anda bisa berupa "sentinel" yang hanya mendukung !=
dengan tipe iterator begin.
Contoh praktis mengapa ini berguna adalah bahwa iterator akhir Anda dapat membaca "periksa Anda char*
untuk melihat apakah itu menunjuk '0'
" ketika ==
dengan a char*
. Ini memungkinkan rentang C ++ untuk ekspresi menghasilkan kode yang optimal ketika iterasi lebih dari char*
buffer null-dihentikan .
struct null_sentinal_t {
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator==(Rhs const& ptr, null_sentinal_t) {
return !*ptr;
}
template<class Rhs,
std::enable_if_t<!std::is_same<Rhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(Rhs const& ptr, null_sentinal_t) {
return !(ptr==null_sentinal_t{});
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator==(null_sentinal_t, Lhs const& ptr) {
return !*ptr;
}
template<class Lhs,
std::enable_if_t<!std::is_same<Lhs, null_sentinal_t>{},int> =0
>
friend bool operator!=(null_sentinal_t, Lhs const& ptr) {
return !(null_sentinal_t{}==ptr);
}
friend bool operator==(null_sentinal_t, null_sentinal_t) {
return true;
}
friend bool operator!=(null_sentinal_t, null_sentinal_t) {
return false;
}
};
contoh langsung dalam kompiler tanpa dukungan penuh C ++ 17; for
loop diperluas secara manual.
begin/end
atau teman, statis atau gratisbegin/end
. Hanya berhati-hatilah di namespace mana Anda meletakkan fungsi gratis: stackoverflow.com/questions/28242073/…