Standar telah diubah sejak pertanyaan (dan sebagian besar jawaban) diposting dalam resolusi laporan cacat ini .
Cara membuat for(:)loop bekerja pada tipe Anda Xsekarang 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 constvariasi. 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_exprdan end_expradalah 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_declarationdengan, 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_expruntuk 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::begintidak dipanggil kecuali range_expressionmengembalikan objek bertipe namespace stdatau 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 __begindan __endtelah 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; forloop diperluas secara manual.
begin/endatau teman, statis atau gratisbegin/end. Hanya berhati-hatilah di namespace mana Anda meletakkan fungsi gratis: stackoverflow.com/questions/28242073/…