loop instead for_each for based c++ for-loop range c++11 argument-dependent-lookup

instead - for_each() c++



Rango basado en redundancia de definiciĆ³n de sentencia (1)

Mirando n3092, en §6.5.4 encontramos la equivalencia para un ciclo basado en rango para. Luego continúa diciendo a qué __begin y __end son iguales. Diferencia entre arreglos y otros tipos, y encuentro esto redundante (también confuso).

Dice que para los tipos de arrays que __begin y __end son lo que usted espera: un puntero al primero y un puntero al final del pasado. Luego, para otros tipos, __begin y __end son iguales para begin(__range) y end(__range) , con ADL. El espacio de nombres std está asociado, para encontrar el std::begin y std::end definido en <iterator> iterator <iterator> , §24.6.5.

Sin embargo, si nos fijamos en la definición de std::begin y std::end , ambas están definidas para matrices y tipos de contenedores. Y las versiones de matriz hacen exactamente lo mismo que arriba: apuntan a la primera, apuntan a una y más allá del final.

¿Por qué es necesario diferenciar las matrices de otros tipos, cuando la definición dada para otros tipos funcionaría igual de bien, encontrando std::begin y std::end ?

Algunas citas resumidas por conveniencia:

§6.5.4 El rango basado for declaración

- si _RangeT es un tipo de matriz, begin-expr y end-expr son __range y __range + __bound, respectivamente, donde __bound es la matriz enlazada. Si _RangeT es una matriz de tamaño desconocido o una matriz de tipo incompleto, el programa está mal formado.

- de lo contrario, begin-expr y end-expr son begin (__ range) y end (__ range), respectivamente, donde begin y end se buscan con búsqueda dependiente del argumento (3.4.2). Para los fines de esta búsqueda de nombres, namespace std es un espacio de nombres asociado.

§24.6.5 rango de acceso

template <class T, size_t N> T* begin(T (&array)[N]);

Devoluciones: matriz.

template <class T, size_t N> T* end(T (&array)[N]);

Devuelve: array + N.


Esto evita un caso de esquina con ADL:

namespace other { struct T {}; int begin(T*) { return 42; } } other::T a[3]; for (auto v : a) {}

Debido a que ADL encuentra otro :: comience cuando la llamada begin(a) , el código equivalente se rompería y causaría un error de compilación confuso (en la línea de "no se puede comparar int con otro :: T *" como el end(a) devolvería un T *) o comportamiento diferente (si se definió otro :: final e hizo algo igualmente inesperado).