URL: https://linuxfr.org/users/julien_jorge/journaux/constexpr-versus-template Title: Constexpr versus template Authors: Julien Jorge Date: 2021年04月23日T13:57:15+02:00 License: CC By-SA Tags: Score: 29 Bonjour 'nal, J'étais tranquille, en train de m'occuper de mes propres affaires, quand soudain je me suis demandé si l'utilisation de `constexpr` introduit dans C++11 pouvait réduire les temps de compilation par rapport à la méthode précédente de la métaprogrammation via des templates. Pour rappel, l'idée de `constexpr` est d'indiquer au compilateur que la fonction ou variable concernée peut être calculée à la compilation si tous ses paramètres sont connus, et doit être calculée ainsi si elle apparaît dans un contexte d'expression constante (par exemple un paramètre de template). Prenons cette chouette fonction pour illustrer : ```c++ // Calcule n en additionnant des 1 n fois. // CC-BY-SA-NC-ND, patent pending. unsigned count(unsigned n) { return (n == 0) ? 0 : 1 + count(n - 1); } ``` Si je voulais utiliser cette fonction dans un contexte où une constante de compilation est nécessaire, en C++98 je ne pourrais pas: ```c++ // count() est compilée et évaluée à l'exécution, ce qui est une // erreur: les tableaux de taille variable ne sont pas conformes // au standard. int array[count(24)]; ``` Pour contourner cela une solution est faire le calcul dans un type, via de la métaprogrammation avec templates: ```c++ template struct count_t; // le cas d'arrêt template struct count_t<0> { enum { value = 0 }; }; // le calcul récursif pour le cas général. template struct count_t { enum { value = 1 + count_t::value }; }; ``` Et là tu vas me dire que c'est pas très _DRY_. Je me retrouve avec deux implémentations du même calcul, l'un est pour être effectué à la compilation et l'autre à l'exécution. Cela ne serait-il pas mieux si la même implémentation pouvait être utilisée pour les deux cas ? _`constexpr` enters the chat._ En C++11 il suffit de déclarer la fonction avec le mot clé `constexpr` pour qu'elle soit utilisable à la compilation (en gros hein, je simplifie pour l'exemple) : ```c++ constexpr int count(unsigned n) { return (n == 0) ? 0 : 1 + count(n - 1); } void foo() { // Pouf ! Ça marche. int array[count(24)]; } ``` Accessoirement il me semble que cette possibilité a aussi l'avantage de contourner la limite d'instanciations récursives des templates imposée par le compilateur. Revenons à l'interrogation initiale. Tu n'es pas sans ignorer que la métaprogrammation à base de templates met à genoux les compilateurs. C'est la 3è plus grosse consommation d'électricité et plus gros producteur de CO2 depuis 1876. Est-ce que la version `constexpr` est aussi coûteuse ? Pour comparer tout ça j'ai lancé la compilation des exemples ci-dessus en boucle, de 50 à 500 fois, et j'ai mesuré le temps que prenait la boucle, en secondes. Le tout avec G++ 9.3. Au final ça donne ça: ``` # nombre de compilations, templates (s.), constexpr (s.) 50, 1.193, 0.596 100, 2.218, 1.252 150, 3.449, 1.763 200, 4.628, 2.358 250, 5.975, 2.984 300, 7.022, 3.484 350, 8.067, 4.132 400, 9.237, 4.870 450, 10.300, 5.344 500, 11.410, 5.835 ``` Voilà, ça compile à peu près deux fois plus rapidement en utilisant la version constexpr que la version templates. À titre de comparaison, compiler 500 fois un fichier vide prend environ 4 secondes.

AltStyle によって変換されたページ (->オリジナル) /