Rozważmy określenie zakres oparty na Loop rozpocząć lista_wyrażeń_sortowania i końcowego wyrażenie (N4140 [stmt.ranged]/P1). Biorąc pod uwagę zakres __range
typu _RangeT
,symulujących koniec zachowanie zakres oparty na pętli rozpocznijmy/
rozpocząć lista_wyrażeń_sortowania i końcową lista_wyrażeń_sortowania są określone w następujący sposób:
- jeśli
_RangeT
jest typu tablicą rozpocząć lista_wyrażeń_sortowania i koniec-wyr. to odpowiednio__range
i__range + __bound
, gdzie__bound
jest związana tablica. Jeśli_RangeT
jest tablicą o nieznanym rozmiarze lub macierzą niekompletnego typu, program jest źle sformułowany;- jeśli
_RangeT
to typ klasy, niewykwalifikowany ID sbegin
iend
porównywane są z zakresu klasy_RangeT
jakby dostępu członka klasy przeglądowej (3.4.5) i jeśli jedna (lub obu) znajduje się co najmniej jeden deklaracja rozpocząć lista_wyrażeń_sortowania i końcową lista_wyrażeń_sortowania są__range.begin()
i__range.end()
, odpowiednio;- inaczej rozpocząć lista_wyrażeń_sortowania i końcową lista_wyrażeń_sortowania są
begin(__range)
iend(__range)
, odpowiednio, gdziebegin
iend
porównywane są z przynależne nazw (3.4.2). [Uwaga: Zwykłe nieuwzględnione badanie (3.4.1) nie jest wykonywane. - koniec uwaga]
Czy to możliwe, aby symulować ten dokładnie zachowanie zwykłego kodu C++? to znaczy, możemy napisać magic_begin
i szablon magic_end
funkcja taka, że
for(auto&& p : range_init) { /* statements */ }
i
{
auto&& my_range = range_init;
for(auto b = magic_begin(my_range), e = magic_end(my_range); b != e; ++b){
auto&& p = *b;
/* statements */
}
}
zawsze mają dokładnie ten sam problem?
Non-odpowiedzi obejmują wykwalifikowanych połączeń do std::begin
/std::end
(nie zajmuje trzecią kulę, między innymi) i using std::begin; begin(range);
ponieważ, między innymi, że jest niejednoznaczne jeśli ADL dla begin
stwierdzi przeciążenie, który jest równie dobry jak std::begin
.
Dla ilustracji, zważywszy
namespace foo {
struct A { int begin; };
struct B { using end = int; };
class C { int* begin(); int *end(); }; // inaccessible
struct D { int* begin(int); int* end();};
struct E {};
template<class T> int* begin(T&) { return nullptr; }
template<class T> int* end(T&) { return nullptr; }
}
foo::A a; foo::B b; foo::C c; foo::D d; foo::E e;
Chcę magic_begin(a)
/magic_begin(b)
/magic_begin(c)
/magic_begin(d)
być błąd kompilacji, a magic_begin(e)
wrócić (int*)nullptr
.
Masz na myśli, że 'magic_end' jest błędem kompilacji dla' b', prawda? – Columbo
@ Columbo Cóż, jeśli podążamy za specyfikacją opartą na zasięgu, to oba są błędami. Ale jestem zadowolony z tego, że "przynajmniej jeden z" magic_begin' i 'magic_end' powoduje błąd". –
Och, przepraszam! Błędne odczytanie drugiego punktu. – Columbo