Bonjour, cher lecteur!
Cet article est le deuxième d'une série d'articles abstraits que j'écrirai en lisant le livre à succès de Scott Meyers, Effective and Modern c ++. Chacun de ces articles aura un répertoire distinct dans un projet spécialement mis en place sur github.com avec des exemples en direct d'utilisation de ce que nous lisons aujourd'hui.
Cet article complète les règles d'inférence de type de l'article précédent et traite de certains aspects de l'inférence de type de modèle pour les arguments qui sont un tableau et une fonction.
Inférence de type de modèle pour le tableau
Le compilateur c ++ a une telle propriété qu'un tableau déclaré, toujours lorsqu'il est transmis à une fonction de modèle avec un paramètre déclaré non comme un lien, est toujours converti en un pointeur vers le type stocké et vice versa, si le paramètre est déclaré en tant que lien, alors une telle conversion n'est pas effectuée.
Fonctions du modèle:
Pour commencer, je donnerai le code des fonctions modèles qui déduisent les types convoités, puis le processus de dérivation lui-même:
template<typename T> void paramDeductInfo(T param, const char *initType) { std::cout << initType << " -> (T param) -> " << type_id_with_cvr<T>().pretty_name() << std::endl; }; template<typename T> void refParamDeductInfo(T ¶m, const char *initType) { std::cout << initType << " -> (T ¶m) -> " << type_id_with_cvr<T>().pretty_name() << std::endl; };
Inférence de type:
cli::printCaption("TYPE DEDUCTION FOR ARRAY OF CHAR"); char charSeq[] = "Hi everyone!"; paramDeductInfo(charSeq, "char []"); refParamDeductInfo(charSeq, "char []"); cli::printCaption("TYPE DEDUCTION FOR ARRAY OF INT"); int intSeq[] = {1, 2, 3}; paramDeductInfo(intSeq, "int []"); refParamDeductInfo(intSeq, "int []"); cli::printCaption("TYPE DEDUCTION FOR ARRAY OF CLASS A"); class A { } const classASeq[] = {A(), A(), A()}; paramDeductInfo(classASeq, "class A[]"); refParamDeductInfo(classASeq, "class A[]");
Le pseudo-code suivant reflète la sortie vers la console de ces instructions:
************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF CHAR ************************************************************************************************************************ char [] -> (T param) -> char* char [] -> (T ¶m) -> char [13] ************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF INT ************************************************************************************************************************ int [] -> (T param) -> int* int [] -> (T ¶m) -> int [3] ************************************************************************************************************************ TYPE DEDUCTION FOR ARRAY OF CLASS A ************************************************************************************************************************ class A[] -> (T param) -> main::A const* class A[] -> (T ¶m) -> main::A const [3]
Exemple 1 - analyse de la longueur d'un tableau au moment de la compilation
De plus, le type de sortie du tableau stocke des informations sur sa taille, qui peuvent être utilisées dans une fonction de modèle pour manipuler la taille du tableau lors de la compilation ou pour générer du code plus efficace.
J'ai utilisé cette fonctionnalité dans la fonction printCaption pour limiter la longueur de l'en-tête affiché sur la ligne de commande au moment de la compilation. Un peu, mais sympa.
namespace cli { template<typename T, std::size_t N> constexpr void printCaption(T (&capValue)[N]) { static_assert(N <= 121, "caption length should be less than 120"); std::cout << std::endl << "*******************************************************************************" << std::endl << capValue << std::endl << "*******************************************************************************" << std::endl << std::endl; }; }
Vérifions s'il y aura une erreur si nous introduisons un en-tête manifestement inapproprié.
cli::printCaption("123456789 123456789 123456789 123456789 123456789 123456789 123456789" "123456789 123456789 123456789 123456789 123456789 !");
Et vous voilà, s'il vous plaît, eh bien, n'est-ce pas merveilleux?
/...sources/cli.h:12:3: error: static assertion failed: caption length should be less than 120 static_assert(N <= 121, "caption length should be less than 120"); ^~~~~~~~~~~~~
Exemple 2 - foreach sur un tableau en mémoire
Je pense que voici une autre telle approche qui peut sembler utile si nous avons une taille de tableau au moment de la compilation, pourquoi ne pas l'utiliser pour organiser une boucle sur un tel tableau?
template<typename T, size_t N, typename F> void forEachOnAnArray(T (&inmemArray)[N], F &callback) { for (int i = 0; i < N; ++i) callback(inmemArray[i]); };
L'utilisation de cette fonction est la suivante:
auto printInt = [](int value) { std::cout << " " << value; }; forEachOnAnArray(intSeq, printInt);
En général, l'utilisation de cette fonction n'est en aucun cas limitée à l'extraction de la taille de la baie.
Inférence de type pour une fonction
Parler d'inférence de type pour la fonction Meyers est concis. Il mentionne exactement qu'ils sont réduits à un pointeur de la même manière que pour les tableaux, sauf lorsque le paramètre de la fonction modèle par laquelle notre type de fonction doit être affiché n'est pas déclaré en tant que lien.
Il aurait probablement dû parler d'une sorte d'encapsuleur de modèle pour les fonctions, mais je suppose que cela va au-delà de la question du c ++ efficace et moderne.
Nous, mon cher lecteur, reviendrons certainement sur ce numéro!
Merci et bonne journée !!