Il me semble qu'avoir une "fonction qui renvoie toujours 5" brise ou dilue le sens de "appeler une fonction". Il doit y avoir une raison, ou un besoin pour cette capacité, sinon ce ne serait pas en C ++ 11. Pourquoi est-il là?
// preprocessor.
#define MEANING_OF_LIFE 42
// constants:
const int MeaningOfLife = 42;
// constexpr-function:
constexpr int MeaningOfLife () { return 42; }
Il me semble que si j'écrivais une fonction qui retourne une valeur littérale et que j'arrivais à une révision de code, quelqu'un me dirait, je devrais alors, déclarer une valeur constante au lieu d'écrire return 5.
constexpr
? Si oui, je peux voir une utilisation.const
. En fait, l' intention prescrite est utile ! Les dimensions des tableaux sont l'exemple canonique.Réponses:
Supposons qu'il fasse quelque chose d'un peu plus compliqué.
Vous avez maintenant quelque chose qui peut être évalué à une constante tout en conservant une bonne lisibilité et en permettant un traitement légèrement plus complexe que de simplement définir une constante sur un nombre.
Il fournit essentiellement une bonne aide à la maintenabilité car il devient plus évident de savoir ce que vous faites. Prenons
max( a, b )
par exemple:C'est un choix assez simple, mais cela signifie que si vous appelez
max
avec des valeurs constantes, il est explicitement calculé au moment de la compilation et non au moment de l'exécution.Un autre bon exemple serait une
DegreesToRadians
fonction. Tout le monde trouve les degrés plus faciles à lire que les radians. Bien que vous sachiez que 180 degrés sont en radians, il est beaucoup plus clair comme suit:Beaucoup de bonnes informations ici:
http://en.cppreference.com/w/cpp/language/constexpr
la source
introduction
constexpr
n'a pas été présenté comme un moyen de dire à l'implémentation que quelque chose peut être évalué dans un contexte qui nécessite une expression constante ; les implémentations conformes ont pu le prouver avant C ++ 11.Quelque chose qu'une implémentation ne peut pas prouver, c'est l' intention d'un certain morceau de code:
De quoi le monde serait-il privé
constexpr
?Disons que vous développez une bibliothèque et réalisez que vous voulez pouvoir calculer la somme de chaque entier de l'intervalle
(0,N]
.Le manque d'intention
Un compilateur peut facilement prouver que la fonction ci-dessus peut être appelée dans une expression constante si l'argument passé est connu pendant la traduction; mais vous n'avez pas déclaré cela comme une intention - il se trouve que c'est le cas.
Maintenant, quelqu'un d'autre arrive, lit votre fonction, fait la même analyse que le compilateur; " Oh, cette fonction est utilisable dans une expression constante!" et écrit le code suivant.
L'optimisation
En tant que développeur de bibliothèque "génial" , vous décidez que
f
le résultat devrait être mis en cache lors de son appel; qui voudrait calculer le même ensemble de valeurs encore et encore?Le résultat
En introduisant votre optimisation idiote, vous venez de rompre chaque utilisation de votre fonction qui se trouvait dans un contexte où une expression constante était requise.
Vous n'avez jamais promis que la fonction était utilisable dans une expression constante , et sans quoi
constexpr
il n'y aurait aucun moyen de fournir une telle promesse.Alors, pourquoi avons-nous besoin
constexpr
?L'utilisation principale de constexpr est de déclarer l' intention .
Si une entité n'est pas marquée comme
constexpr
- elle n'a jamais été destinée à être utilisée dans une expression constante ; et même si c'est le cas, nous comptons sur le compilateur pour diagnostiquer un tel contexte (car il ne tient pas compte de notre intention).la source
constexpr
expressions. En d'autres termes, à peu près tout peut être annotéconstexpr
(peut-être qu'un jour, il disparaîtra simplement à cause de cela?), Et à moins que l'on ait un critère de moment à utiliserconstexpr
ou non, presque tout le code sera écrit comme tel .I/O
,syscall
etdynamic memory allocation
ne peut certainement pas être marqué commeconstexpr
En outre, tout ne devrait pas l'êtreconstexpr
.constexpr
est la garantie d'une sorte de comportement. Tout comme leconst
fait.int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)];
ne pas pouvoir compiler ça n'importe où?Prenez
std::numeric_limits<T>::max()
: pour une raison quelconque, c'est une méthode.constexpr
serait bénéfique ici.Un autre exemple: vous voulez déclarer un C-array (ou a
std::array
) qui est aussi grand qu'un autre tableau. La façon de procéder pour le moment est la suivante:Mais ne serait-il pas préférable de pouvoir écrire:
Grâce à
constexpr
, vous pouvez:la source
constexpr
force le compliant à faire en sorte que la fonction renvoie une valeur au moment de la compilation (si elle le peut).constexpr
il ne peut pas être utilisé dans une déclaration de taille de tableau, ni comme argument de modèle, que le résultat de l'appel de fonction soit ou non une constante de compilation. Ces deux sont fondamentalement les seuls cas d'utilisation,constexpr
mais au moins le cas d'utilisation de l'argument modèle est assez important.-pedantic
option et elle sera signalée comme une erreur.constexpr
les fonctions sont vraiment sympa et un excellent ajout à c ++. Cependant, vous avez raison en ce que la plupart des problèmes qu'il résout peuvent être contournés de manière non élégante avec les macros.Cependant, l'une des utilisations de
constexpr
n'a pas de constantes typées C ++ 03 équivalentes.la source
four
ne se résout pas. J'ai dû vraiment creuser pour savoir qui prenait l'adresse de mastatic const
variable.four
nifive
sont dans la portée.enum class
type, il corrige certains des problèmes d'énumération.D'après ce que j'ai lu, le besoin de constexpr provient d'un problème de métaprogrammation. Les classes de traits peuvent avoir des constantes représentées comme des fonctions, pensez: numeric_limits :: max (). Avec constexpr, ces types de fonctions peuvent être utilisés dans la métaprogrammation, ou comme limites de tableau, etc., etc.
Un autre exemple hors de ma tête serait que pour les interfaces de classe, vous voudrez peut-être que les types dérivés définissent leurs propres constantes pour certaines opérations.
Éditer:
Après farfouillé sur le SO, il semble que d' autres sont venus avec quelques exemples de ce qui pourrait être possible avec constexprs.
la source
constexpr
est plus spécifiquement utile dans un compilateur doté d'un puissant système d'évaluation des expressions à la compilation. C ++ n'a vraiment aucun homologue dans ce domaine. (c'est un éloge fort pour C ++ 11, à mon humble avis)Extrait du discours de Stroustrup à "Going Native 2012":
la source
Une autre utilisation (non encore mentionnée) est celle des
constexpr
constructeurs. Cela permet de créer des constantes de temps de compilation qui n'ont pas besoin d'être initialisées pendant l'exécution.Associez cela à des littéraux définis par l'utilisateur et vous avez une prise en charge complète des classes définies par l'utilisateur littérales.
la source
Il y avait un schéma avec la métaprogrammation:
Je crois qu'il a
constexpr
été introduit pour vous permettre d'écrire de telles constructions sans avoir besoin de modèles et de constructions étranges avec spécialisation, SFINAE et d'autres choses - mais exactement comme vous écririez une fonction d'exécution, mais avec la garantie que le résultat sera déterminé lors de la compilation -temps.Cependant, notez que:
Compilez ceci avec
g++ -O3
et vous verrez que celafact(10)
est en effet évalué au moment de la compilation!Un compilateur compatible VLA (donc un compilateur C en mode C99 ou un compilateur C ++ avec des extensions C99) peut même vous permettre de faire:
Mais que ce soit du C ++ non standard pour le moment -
constexpr
ressemble à un moyen de lutter contre cela (même sans VLA, dans le cas ci-dessus). Et il y a toujours le problème de la nécessité d'avoir des expressions constantes "formelles" comme arguments de modèle.la source
std::array<int, fact(2)>
et vous verrez que fact () n'est pas évalué au moment de la compilation. C'est juste l'optimiseur GCC qui fait du bon travail.Je viens de commencer à basculer un projet vers c ++ 11 et j'ai trouvé une situation parfaitement bonne pour constexpr qui nettoie les méthodes alternatives pour effectuer la même opération. Le point clé ici est que vous ne pouvez placer la fonction dans la déclaration de taille de tableau que lorsqu'elle est déclarée constexpr. Il y a un certain nombre de situations où je peux voir que cela est très utile pour aller de l'avant avec le domaine du code dans lequel je suis impliqué.
la source
static inline constexpr const auto
c'est probablement mieux.Toutes les autres réponses sont excellentes, je veux juste donner un exemple sympa d'une chose que vous pouvez faire avec constexpr qui est incroyable. See-Phit ( https://github.com/rep-movsd/see-phit/blob/master/seephit.h ) est un analyseur HTML et un moteur de modèle au moment de la compilation. Cela signifie que vous pouvez mettre du HTML et en sortir un arbre qui peut être manipulé. Faire l'analyse syntaxique au moment de la compilation peut vous donner un peu de performances supplémentaires.
À partir de l'exemple de page github:
la source
Votre exemple de base sert le même argument que celui des constantes elles-mêmes. Pourquoi utiliser
plus de
Parce que c'est beaucoup plus maintenable. L'utilisation de constexpr est beaucoup, beaucoup plus rapide à écrire et à lire que les techniques de métaprogrammation existantes.
la source
Il peut permettre de nouvelles optimisations.
const
est traditionnellement un indice pour le système de type, et ne peut pas être utilisé pour l'optimisation (par exemple, uneconst
fonction membre peutconst_cast
et modifie l'objet de toute façon, légalement, doncconst
ne peut pas faire confiance pour l'optimisation).constexpr
signifie que l'expression est vraiment constante, à condition que les entrées de la fonction soient const. Considérer:Si cela est exposé dans un autre module, le compilateur ne peut pas faire confiance qui
GetNumber()
ne renverra pas de valeurs différentes à chaque appel - même consécutivement sans appels non const entre - parce queconst
aurait pu être rejeté dans l'implémentation. (Évidemment, tout programmeur qui a fait cela devrait être abattu, mais le langage le permet, donc le compilateur doit respecter les règles.)Ajout
constexpr
:Le compilateur peut désormais appliquer une optimisation dans laquelle la valeur de retour de
GetNumber()
est mise en cache et éliminer les appels supplémentaires àGetNumber()
, carconstexpr
c'est une garantie plus forte que la valeur de retour ne changera pas.la source
const
peut être utilisé dans l'optimisation ... C'est un comportement indéfini de modifier une valeur définie const même après unconst_cast
IIRC. Je m'attendrais à ce qu'il soit cohérent pourconst
les fonctions des membres, mais je devrais vérifier cela avec la norme. Cela signifierait que le compilateur peut y effectuer des optimisations en toute sécurité.int x
vs.const int x
), alors il est sûr de le modifier enconst_cast
supprimant const sur un pointeur / une référence à lui. Sinon,const_cast
invoquerait toujours un comportement indéfini et serait inutile :) Dans ce cas, le compilateur n'a aucune information sur la constance de l'objet d'origine, donc il ne peut pas le dire.int GetNumber() const = 0;
) doit déclarer laGetNumber()
méthode virtuelle. Le second (constexpr int GetNumber() const = 0;
) n'est pas valide car le spécificateur pur (= 0
) implique que la méthode soit virtuelle, mais les constexpr ne doivent pas être virtuelles (ref: en.cppreference.com/w/cpp/language/constexpr )Quand utiliser
constexpr
:la source
constexpr
devrait être préférée aux macros de préprocesseur ouconst
.C'est utile pour quelque chose comme
Liez-le avec une classe de traits ou similaire et cela devient très utile.
la source