Quelqu’un peut-il expliquer ce code de modèle qui me donne la taille d’un tableau?

template size_t array_size(const T (&)[n]) { return n; } 

La partie que je ne comprends pas est les parameters de cette fonction de modèle. Que se passe-t-il avec le tableau quand je le passe à travers cela qui donne n le nombre d’éléments dans le tableau?

Eh bien, vous devez d’abord comprendre qu’essayer d’obtenir une valeur à partir d’un tableau peut vous donner un pointeur sur son premier élément:

 int a[] = {1, 2, 3}; int *ap = a; // a pointer, size is lost int (&ar)[3] = a; // a reference to the array, size is not lost 

Les références font référence à des objects utilisant leur type exact ou leur type de classe de base. La clé est que le modèle prend des tableaux par référence. Les tableaux (pas les références à eux) en tant que parameters n’existent pas en C ++. Si vous atsortingbuez à un paramètre un type de tableau, ce sera plutôt un pointeur. L’utilisation d’une référence est donc nécessaire lorsque l’on veut connaître la taille du tableau transmis. La taille et le type d’élément sont automatiquement déduits, comme c’est généralement le cas pour les modèles de fonction. Le modèle suivant

 template size_t array_size(const T (&)[n]) { return n; } 

Appelé avec notre tableau précédemment défini a va instancier implicitement la fonction suivante:

 size_t array_size(const int (&)[3]) { return 3; } 

Qui peut être utilisé comme ceci:

 size_t size_of_a = array_size(a); 

Il y a une variante que j’ai inventée il y a quelque temps [Edit: il s’avère que quelqu’un a déjà eu la même idée ici ] qui peut déterminer une valeur au moment de la compilation. Au lieu de renvoyer directement la valeur, le modèle renvoie un type de retour dépendant de n :

 template char (& array_size(const T (&)[n]) )[n]; 

Vous dites que si le tableau a n éléments, le type de retour est une référence à un tableau ayant la taille n et le type d’élément char . Maintenant, vous pouvez obtenir une taille déterminée à la compilation du tableau passé:

 size_t size_of_a = sizeof(array_size(a)); 

Comme un tableau de caractères possédant n éléments a une taille n , cela vous donnera également le nombre d’éléments dans le tableau donné. Au moment de la compilation, vous pouvez donc faire

 int havingSameSize[sizeof(array_size(a))]; 

Comme la fonction n’est jamais appelée, elle n’a pas besoin d’être définie, elle n’a donc pas de corps. J’espère que je pourrais clarifier un peu la question.

Pensez-y de cette façon, supposons que vous ayez un tas de fonctions:

 // Note that you don't need to name the array, since you don't // actually reference the parameter at all. size_t array_size(const int (&)[1]) { return 1; } size_t array_size(const int (&)[2]) { return 2; } size_t array_size(const int (&)[3]) { return 3; } // etc... 

Maintenant, quand vous appelez cela, quelle fonction est appelée?

 int a[2]; array_size(a); 

Maintenant, si vous mettez en forme l’arraysize, vous obtenez:

 template  size_t array_size(const int (&)[n]) { return n; } 

Le compilateur tentera d’instancier une version de array_size qui correspond au paramètre avec lequel vous l’appelez. Donc, si vous l’appelez avec un tableau de 10 ints, il va instancier array_size avec n = 10.

Ensuite, modélisez simplement le type afin de pouvoir l’appeler avec plus que des tableaux int:

 template  size_t array_size(const T (&)[n]) { return n; } 

Et tu as fini.

Edit : Une note sur le (&)

Les parenthèses sont nécessaires autour de la & pour différencier le tableau des références int (illégal) et la référence au tableau des ints (ce que vous voulez). Puisque la préséance de [] est supérieure à & , si vous avez la déclaration:

 const int &a[1]; 

En raison de la priorité des opérateurs, vous obtenez un tableau à un élément de références const à int. Si vous voulez que le & appliqué en premier, vous devez forcer cela avec des parenthèses:

 const int (&a)[1]; 

Maintenant, vous avez une référence const à un tableau d’éléments ints. Dans la liste des parameters de la fonction, vous n’avez pas besoin de spécifier le nom d’un paramètre si vous ne l’utilisez pas. Vous pouvez donc supprimer le nom, mais conserver les parenthèses:

 size_t array_size(const int (&)[1]) 

Rien n’arrive au tableau. C’est un paramètre inutilisé utilisé pour résoudre la signature de la fonction de modèle.

Il ne peut pas non plus être utilisé comme argument de modèle, mais c’est un élément distinct.

Une façon un peu étrange d’obtenir le résultat en tant que const comstack-time pour ceux d’entre nous qui n’ont pas “constexpr”:

 #include  namespace { template  struct helper { enum { value = V }; }; template auto get_size(T(&)[Size]) -> helper < Size > { return helper < Size >() ; } template struct get_value { enum { value = T::value }; }; } int main() { std::cout << get_value::value; }