¿Cómo std :: end conoce el final de una matriz?

std::begin y std::end conocen el principio y el final de un container o una array .

Es muy fácil conocer el end y el begin de un vector por ejemplo, porque es una clase que proporciona esta información. Pero, ¿cómo sabe el final de una array como la siguiente?

 int simple_array[5]{1, 2, 3, 4, 5}; auto beg=std::begin(simple_array); auto en=std::end(simple_array); 

std::begin no es tan difícil saber dónde comienza la matriz. Pero, ¿cómo sabe dónde termina? ¿Se almacenará el entero constante 5 alguna parte?

Agradecería que obtuviera una respuesta con información de bajo nivel.

es el entero constante 5 se almacenará en algún lugar?

Sí, es parte del tipo de matriz. Pero no, no está almacenado en ningún lugar de manera explícita. Cuando tengas

 int i[5] = { }; 

el tipo de i es int[5] . La respuesta de Shafik habla de cómo se usa esta longitud para implementar el end .

Si tienes C ++ 11, usar constexpr sería la forma más fácil de hacerlo

 template  inline constexpr size_t arrLen(const T (&arr) [N]) { return N; } 

Si tiene un comstackdor anterior a C ++ 11 donde constexpr no está disponible, la función anterior puede no evaluarse en tiempo de comstackción. Entonces en tales situaciones, puedes usar esto:

 template  char (&arrLenFn(const T (&arr) [N]))[N]; #define arrLen(arr) sizeof(arrLenFn(arr)) 

Primero declaramos una función que devuelve una referencia a una matriz de N char es decir, el sizeof esta función ahora sería la longitud de la matriz. Luego tenemos una macro para envolverlo, para que sea legible al final de la persona que llama.

Nota: Dos matrices del mismo tipo base pero con longitudes diferentes siguen siendo dos tipos completamente diferentes. int[3] no es lo mismo que int[2] . La descomposición de la matriz , sin embargo, le daría una int* en ambos casos. Leer ¿Cómo uso las matrices en C ++? si quieres saber más

Pero, ¿cómo sabe el final de una matriz

Utiliza un parámetro de plantilla sin tipo para deducir el tamaño de la matriz, que luego se puede utilizar para generar el puntero final. La firma C ++ 11 de la sección cppreference para std :: end es la siguiente:

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

Como notas de HDV, dado que se pasa por referencia, esto evita la disminución de un puntero.

La implementación sería algo similar a:

 template< class T, std::size_t N > T* end( T (&array)[N] ) { return array + N ; } 

¿El entero constante 5 se almacenará en algún lugar?

5 o N es parte del tipo de matriz y, por lo tanto, N está disponible en tiempo de comstackción. Por ejemplo, al aplicar sizeof a una matriz, obtendremos el número total de bytes en la matriz.

Muchas veces vemos una matriz pasada por valor a una función. En ese caso, la matriz se desintegra a un puntero al tipo almacenado en la matriz. Entonces ahora se pierde la información de tamaño. Pasar por referencia nos permite evitar esta pérdida de información y extraer el tamaño N del tipo.

Porque está pasando una matriz a std::end , y una matriz tiene tipo T [N] . std::end puede decir cuándo finaliza la matriz mirando el N en el tipo.