Simulando el rango basado en el comportamiento de inicio / fin del ciclo
Considere la especificación del rango basado en buclesbegin-expr yend-expr (N4140 [stmt.ranged] / p1). Dado un rango__range
de tipo_RangeT
,
begin-expr yend-expr se determinan de la siguiente manera:
Si_RangeT
es un tipo de matriz,begin-expr yend-expr son__range
y__range + __bound
, respectivamente, donde__bound
es la matriz unida. Si_RangeT
es una matriz de tamaño desconocido o una matriz de tipo incompleto, el programa está mal formado;Si_RangeT
es un tipo de clase, elid no calificados begin
yend
son buscados en el alcance de la clase_RangeT
como si por la búsqueda de acceso de miembros de la clase (3.4.5), y si cualquiera (o ambos) encuentra al menos una declaración,begin-expr yend-expr son__range.begin()
y__range.end()
, respectivamente;de otra manera,begin-expr yend-expr sonbegin(__range)
yend(__range)
, respectivamente, dondebegin
yend
se buscan en los espacios de nombres asociados (3.4.2). [Nota: La búsqueda ordinaria no calificada (3.4.1) no se realiza. -nota final ]¿Es posible simular esto?exacto comportamiento en código C ++ ordinario? es decir, ¿podemos escribir unmagic_begin
y unmagic_end
plantilla de función tal que
for(auto&& p : range_init) { /* statements */ }
y
{
auto&& my_range = range_init;
for(auto b = magic_begin(my_range), e = magic_end(my_range); b != e; ++b){
auto&& p = *b;
/* statements */
}
}
siempre tiene exactamente el mismo comportamiento?
Las no respuestas incluyen llamadas calificadas astd::begin
/std::end
(no maneja la tercera viñeta, entre otras cosas) yusing std::begin; begin(range);
porque, entre otras cosas, eso es ambiguo si ADL parabegin
encuentra una sobrecarga que es tan buena comostd::begin
.
Por ejemplo, dado
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;
yo quieromagic_begin(a)
/magic_begin(b)
/magic_begin(c)
/magic_begin(d)
ser un error de compilación, ymagic_begin(e)
regresar(int*)nullptr
.