Empêcher le code client de s'attendre à plus que ce que vous promettez
Disons que j'écris une bibliothèque et que j'y ai une fonction qui renvoie une constante :
inline int f() { return 4; }
Si constexpr
n'était pas nécessaire, vous - en tant qu'auteur du code client - pourriez partir et faire quelque chose comme ceci :
int my_array[f()];
Alors je dois changer f()
pour dire renvoyer la valeur d'un fichier de configuration, votre code client serait cassé, mais je n'aurais aucune idée que j'ai risqué de casser votre code. En effet, il se peut que ce ne soit que lorsque vous rencontrez un problème de production et que vous recompilez que vous trouvez ce problème supplémentaire qui vous empêche de reconstruire.
En utilisant constexpr
je documente le fait que le code client peut raisonnablement s'attendre à ce que la fonction reste un élément de l'environnement. constexpr
et l'utiliser comme tel.
Parce que le compilateur a constexpr
il est en mesure de garantir que le code du client n'est pas construit pour dépendre d'un système non compatible avec l'UE. constexpr
selon le scénario ci-dessus - c'est plus que de la documentation : c'est une application au moment de la compilation.
Pourquoi n'y a-t-il pas de diagnostic pour les fonctions "évidemment" jamais constantes ?
Je pense que la confusion ici est due à constexpr
ne garantit pas de manière proactive qu'il existe un ensemble d'arguments pour lequel le résultat est effectivement constant au moment de la compilation : il demande plutôt au programmeur d'en prendre la responsabilité (sinon, le §7.1.5/5 de la norme considère que le programme est mal formé mais ne demande pas au compilateur d'émettre un diagnostic). Oui, c'est malheureux, mais cela n'enlève pas l'utilité de constexpr
.
Donc, peut-être que la question ne devrait pas être "quel est l'intérêt de". constexpr
", mais "pourquoi puis-je compiler une constexpr
qui ne peut jamais retourner une valeur constante". Réponse : parce qu'il serait nécessaire de procéder à une analyse exhaustive des branches qui pourrait impliquer un nombre illimité de combinaisons. Cela pourrait être excessivement coûteux en temps de compilation et/ou en mémoire - même au-delà de la capacité de tout matériel imaginable - à diagnostiquer. De plus, même lorsque cela s'avère pratique, le fait de devoir diagnostiquer de tels cas avec précision est une toute nouvelle boîte de Pandore pour les auteurs de compilateurs (qui sont déjà suffisamment occupés avec l'implémentation de C++11). Il y aurait également des implications pour le programme, telles que la définition des fonctions appelées depuis l'intérieur de l'élément constexpr
qui doit être visible lorsque la validation a été effectuée (et les fonctions que la fonction appelle, etc.).
En attendant, absence de de constexpr
continue d'interdire l'utilisation comme valeur const : la rigueur est sur le sans- constexpr
côté. C'est utile comme illustré ci-dessus.
Comparaison avec les fonctions membres non "constantes".
-
constexpr
empêche int x[f()]
alors que le manque de const
empêche const X x; x.f();
- ils sont tous les deux s'assurer que le code client ne code pas en dur des dépendances non désirées
-
dans les deux cas, vous ne voudriez pas que le compilateur détermine const[expr]
-ness automatiquement :
-
vous ne voudriez pas que le code client appelle une fonction membre sur une const
alors que l'on peut déjà anticiper que cette fonction évoluera pour modifier la valeur observable, cassant ainsi le code client.
-
vous ne voudriez pas qu'une valeur soit utilisée comme paramètre de modèle ou dimension de tableau si vous prévoyez déjà qu'elle sera déterminée plus tard au moment de l'exécution.
-
ils différer dans la mesure où le compilateur impose const
l'utilisation d'autres membres au sein d'une const
mais n'impose pas de résultat constant au moment de la compilation avec la fonction membre constexpr
(en raison des limitations pratiques du compilateur)