Esto es realmente difícil de explicar, pero lo intentaré ...
En primer lugar, dimof
le indica la dimensión o el número de elementos en una matriz. (Creo que "dimensión" es la terminología preferida en los entornos de programación de Windows).
Esto es necesario porque C++
y C
no le brinda una forma nativa de determinar el tamaño de una matriz.
A menudo, las personas suponen sizeof(myArray)
que funcionará, pero eso realmente le dará el tamaño en la memoria, en lugar de la cantidad de elementos. ¡Cada elemento probablemente toma más de 1 byte de memoria!
A continuación, podrían intentarlo sizeof(myArray) / sizeof(myArray[0])
. Esto daría el tamaño en memoria de la matriz, dividido por el tamaño del primer elemento. Está bien, y se usa ampliamente en el C
código. El principal problema con esto es que parecerá funcionar si pasa un puntero en lugar de una matriz. El tamaño de un puntero en la memoria generalmente será de 4 u 8 bytes, aunque lo que señala podría ser una matriz de miles de elementos.
Entonces, lo siguiente que debe probar C++
es usar plantillas para forzar algo que solo funcione para matrices, y dará un error de compilación en un puntero. Se parece a esto:
template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"
La plantilla solo funcionará con una matriz. Deducirá el tipo (no es realmente necesario, pero tiene que estar allí para que la plantilla funcione) y el tamaño de la matriz, luego devuelve el tamaño. La forma en que se escribe la plantilla no puede funcionar con un puntero.
Por lo general, puede detenerse aquí, y esto está en la biblioteca estándar de C ++ como std::size
.
Advertencia: aquí abajo se mete en territorio peludo de lenguaje-abogado.
Esto es bastante bueno, pero aún falla en un caso oscuro:
struct Placeholder {
static float x[8];
};
template <typename T, int N>
int ArraySize (T (&)[N])
{
return N;
}
int main()
{
return ArraySize(Placeholder::x);
}
Tenga en cuenta que la matriz x
se declara , pero no se define . Para llamar a una función (es decir ArraySize
) con ella, se x
debe definir .
In function `main':
SO.cpp:(.text+0x5): undefined reference to `Placeholder::x'
collect2: error: ld returned 1 exit status
No puedes vincular esto.
El código que tiene en la pregunta es una forma de evitarlo. En lugar de llamar realmente a una función, declaramos una función que devuelve un objeto del tamaño exacto . Luego usamos el sizeof
truco en eso.
Se ve igual que llamamos a la función, pero sizeof
es puramente una construcción en tiempo de compilación, por lo que la función nunca en realidad se llama.
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
^^^^ ^ ^^^
// a function that returns a reference to array of N chars - the size of this array in memory will be exactly N bytes
Tenga en cuenta que en realidad no puede devolver una matriz de una función, pero puede devolver una referencia a una matriz.
Entonces DimofSizeHelper(myArray)
es una expresión cuyo tipo es una matriz en N
char
s. La expresión en realidad no tiene que ser ejecutable, pero tiene sentido en tiempo de compilación.
Por sizeof(DimofSizeHelper(myArray))
lo tanto, le dirá el tamaño en tiempo de compilación de lo que obtendría si realmente llamara a la función. Aunque en realidad no lo llamamos.
No te preocupes si ese último bloque no tiene sentido. Es un truco extraño evitar un caso extraño. Es por eso que no escribe este tipo de código usted mismo, y deja que los implementadores de la biblioteca se preocupen por este tipo de tonterías.
std::array
ostd::vector
...