C'est en fait très difficile à expliquer, mais je vais essayer ...
Tout d'abord, dimof
vous indique la dimension ou le nombre d'éléments dans un tableau. (Je crois que "dimension" est la terminologie préférée dans les environnements de programmation Windows).
Ceci est nécessaire car C++
et C
ne vous donne pas de méthode native pour déterminer la taille d'un tableau.
Souvent, les gens supposent que sizeof(myArray)
cela fonctionnera, mais cela vous donnera en fait la taille en mémoire, plutôt que le nombre d'éléments. Chaque élément prend probablement plus d'un octet de mémoire!
Ensuite, ils pourraient essayer sizeof(myArray) / sizeof(myArray[0])
. Cela donnerait la taille en mémoire du tableau, divisée par la taille du premier élément. C'est ok, et largement utilisé dans le C
code. Le problème majeur avec cela est qu'il semble fonctionner si vous passez un pointeur au lieu d'un tableau. La taille d'un pointeur en mémoire sera généralement de 4 ou 8 octets, même si ce qu'il désigne pourrait être un tableau de 1000 éléments.
Donc, la prochaine chose à essayer C++
est d'utiliser des modèles pour forcer quelque chose qui ne fonctionne que pour les tableaux, et donnera une erreur de compilation sur un pointeur. Cela ressemble à ceci:
template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"
Le modèle ne fonctionnera qu'avec un tableau. Il déduira le type (pas vraiment nécessaire, mais doit être là pour que le modèle fonctionne) et la taille du tableau, puis il retourne la taille. La façon dont le modèle est écrit ne peut pas fonctionner avec un pointeur.
Habituellement, vous pouvez vous arrêter ici, et cela se trouve dans le C ++ Standard Libary as std::size
.
Attention: ci-dessous, il pénètre dans le territoire de l'avocat de la langue poilue.
C'est assez cool, mais échoue toujours dans un cas de bord obscur:
struct Placeholder {
static float x[8];
};
template <typename T, int N>
int ArraySize (T (&)[N])
{
return N;
}
int main()
{
return ArraySize(Placeholder::x);
}
Notez que le tableau x
est déclaré , mais non défini . Pour appeler une fonction (ie ArraySize
) avec elle, x
doit être défini .
In function `main':
SO.cpp:(.text+0x5): undefined reference to `Placeholder::x'
collect2: error: ld returned 1 exit status
Vous ne pouvez pas lier cela.
Le code que vous avez dans la question est un moyen de contourner cela. Au lieu d'appeler réellement une fonction, nous déclarons une fonction qui retourne un objet exactement de la bonne taille . Ensuite, nous utilisons l' sizeof
astuce à ce sujet.
Il semble que nous appelions la fonction, mais sizeof
est purement une construction de compilation, donc la fonction n'est jamais réellement appelée.
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
Notez que vous ne pouvez pas réellement renvoyer un tableau à partir d'une fonction, mais vous pouvez renvoyer une référence à un tableau.
Ensuite , DimofSizeHelper(myArray)
est une expression dont le type est un tableau sur l' N
char
art. L'expression n'a pas besoin d'être exécutable, mais elle a du sens au moment de la compilation.
Par conséquent sizeof(DimofSizeHelper(myArray))
, vous indiquera la taille au moment de la compilation de ce que vous obtiendriez si vous appeliez réellement la fonction. Même si nous ne l'appelons pas vraiment.
Ne vous inquiétez pas si ce dernier bloc n'a aucun sens. C'est une astuce bizarre pour contourner un cas de bord bizarre. C'est pourquoi vous n'écrivez pas vous-même ce type de code et laissez les développeurs de bibliothèques s'inquiéter de ce genre de non-sens.
std::array
oustd::vector
....