web-dev-qa-db-fra.com

Comment fonctionne cette fonction de modèle "taille du tableau"?

Doublons possibles:
Quelqu'un peut-il expliquer ce code de modèle qui me donne la taille d'un tableau?
Arguments magiques dans les modèles de fonction…

Quelqu'un peut-il expliquer comment ce code fonctionne? Je sais que le but de ce code est d'obtenir la longueur d'un tableau, mais je ne sais pas comment ce code fonctionne:

template<typename T, int size>
int GetArrLength(T(&)[size]){return size;}

Merci.

47
BobAlmond

Décortiquons d'abord le paramètre, T(&)[size]. Lisez les déclarations de l'intérieur, de droite à gauche, le groupe de parenthèses en premier: c'est un paramètre sans nom qui fait référence à un tableau de taille size de type T.

Autrement dit, il accepte une référence à n'importe quel tableau, où le type et la taille du tableau sont des paramètres de modèle.

Si nous l'appelons comme tel:

int a[10];
GetArrLength(a);

Le compilateur essaiera de déduire les paramètres du modèle. Pour que le type de paramètre corresponde à ce que vous transmettez, T doit être int et size doit être 10 (faisant du paramètre une référence à un tableau de 10 ints).

Vous retournez ensuite cette taille, vous donnant le nombre d'éléments dans un tableau.


Il y a deux "problèmes" avec ce code. Tout d'abord, les tailles ne peuvent pas être négatives, il n'est donc pas logique d'utiliser un type signé comme paramètre de modèle et type de retour. Un type non signé doit plutôt être utilisé; le mieux serait std::size_t:

template<typename T, std::size_t Size>
std::size_t GetArrLength(T(&)[Size]) { return size; }

La seconde est que le résultat de cette fonction n'est pas une expression constante, même si la taille d'un tableau est. Bien que ce soit bien dans la plupart des situations, il serait préférable que nous puissions en obtenir une expression constante. C'est là que vous vous retrouvez avec cette solution:

template <std::size_t N>
struct type_of_size
{
    typedef char type[N];
};

template <typename T, std::size_t Size>
typename type_of_size<Size>::type& sizeof_array_helper(T(&)[Size]);

#define sizeof_array(pArray) sizeof(sizeof_array_helper(pArray))

Ceci est utilisé comme tel:

int a[10];
const std::size_t n = sizeof_array(a); // constant-expression!

Cela fonctionne par trois choses: la première est la même idée que ci-dessus, les paramètres du modèle seront remplis en vous donnant la taille du tableau.

La deuxième partie utilise ces informations pour créer un type avec une taille spécifique, d'où le type_of_size assistant. Cette partie n'est pas strictement nécessaire, mais je pense qu'elle facilite la lecture du code. UNE char[N] a une taille égale à N, toujours, donc nous pouvons abuser de cela pour "stocker" la taille du tableau ... dans la taille d'un type lui-même!

La troisième partie obtient cette taille avec sizeof. Il n'évalue en fait rien, nous n'avons donc pas besoin d'une définition pour la fonction. Il dit simplement "Si vous faisiez cela ... la taille serait ...". Et la taille est notre taille "stockée", dans le tableau char.

58
GManNickG