Partager via


constexpr (C++)

Le mot clé constexpr a été introduit dans C++11 et amélioré dans C++14. Cela signifie expression constante. Comme const, cela peut être appliqué aux variables : une erreur du compilateur est générée lorsque du code tente de modifier la valeur. Contrairement à const, constexpr peut également être appliqué aux fonctions et aux constructeurs de classe. constexpr indique que la valeur, ou la valeur de retour, est constante et, lorsque c’est possible, est calculée lors de la compilation.

Une valeur intégrale constexpr peut être utilisée partout où un entier const est requis, comme dans les arguments de modèle et les déclarations de tableau. Quand une valeur est calculée à la compilation plutôt qu’à l’exécution, cela peut aider votre programme à s’exécuter plus rapidement et à consommer moins de mémoire.

Pour limiter la complexité des calculs constants à la compilation, et leurs impacts potentiels sur le temps de compilation, la norme C++14 exige que les types dans les expressions constantes soient des types littéraux.

Syntaxe

constexpr expression constante del’identificateur= de type littéral;
constexpr identificateurde type littéral{constant-expression} ;
constexpr identificateurde type littéral(params) ;
constexpr ctor(params) ;

Paramètres

params
Un ou plusieurs paramètres, chacun devant être un type littéral et lui-même une expression constante.

Valeur retournée

Une variable ou une fonction constexpr doit retourner un type littéral.

Variables constexpr

La différence principale entre les variables const et constexpr est que l’initialisation d’une variable const peut être différée jusqu’à l’exécution. Une variable constexpr doit être initialisée au moment de la compilation. Toutes les constexpr variables sont const.

  • Une variable peut être déclarée avec constexpr, si elle a un type de littéral et est initialisée. Si l’initialisation est effectuée par un constructeur, le constructeur doit être déclaré comme constexpr.

  • Une référence peut être déclarée comme constexpr lorsque ces deux conditions sont remplies : l’objet référencé est initialisé par une expression constante, et toutes les conversions implicites invoquées lors de l’initialisation sont également des expressions constantes.

  • Toutes les déclarations d’une variable ou fonction constexpr doivent comporter le spécificateur constexpr.

constexpr float x = 42.0;
constexpr float y{108};
constexpr float z = exp(5, 3);
constexpr int i; // Error! Not initialized
int j = 0;
constexpr int k = j + 1; //Error! j not a constant expression

fonctionsconstexpr

Une fonction constexpr est une fonction dont la valeur de retour est calculable au moment de la compilation lorsque le code de consommation en a besoin. Le code consommant nécessite la valeur de retour au moment de la compilation pour initialiser une variable constexpr, ou pour fournir un argument de modèle non de type. Lorsque ses arguments sont des valeurs constexpr, une fonction constexpr produit une constante à la compilation. Si ses arguments constexpr ne sont pas des valeurs , ou si la valeur de retour n’est pas requise au moment de la compilation, la fonction appelée génère une valeur à l’exécution comme une fonction régulière. (Ce double comportement vous évite d’avoir à écrire constexpr et constexpr non versions, de la même fonction.)

Une fonction ou un constructeur constexpr est implicitement inline.

Les règles suivantes s’appliquent également aux fonctionsconstexpr :

  • Une fonction constexpr doit accepter et retourner des types littéraux uniquement.

  • Une fonction constexpr peut être récursive.

  • Avant C++20, une fonction constexpr ne peut pas être virtuelle, et un constructeur ne peut pas être défini comme constexpr lorsque la classe englobante possède des classes de base virtuelles. En C++20 et versions ultérieures, une fonction constexpr peut être virtuelle. Visual Studio 2019 version 16.10 et les versions ultérieures prennent en charge les fonctions constexpr virtuelles lorsque vous spécifiez l’option de compilateur /std:c++20 ou une version ultérieure.

  • Le corps de la fonction peut être défini avec la valeur = default ou = delete.

  • Le corps ne peut contenir aucune instruction goto ou try blocs.

  • Une spécialisation explicite d’un modèle non constexprmodèle peut être déclarée avecconstexpr :

  • Une spécialisation explicite d’un modèle constexpr ne doit pas obligatoirement être déclarée avecconstexpr :

Les règles suivantes s’appliquent aux fonctions constexpr dans Visual Studio 2017 et versions ultérieures :

  • Il peut contenir des instructions if et switch , ainsi que toutes les instructions de bouclage, notamment for, les forbasées sur des plages, les whileet les do-while.

  • Il peut contenir des déclarations de variables locales, mais la variable doit être initialisée. Il doit s’agir d’un type littéral et ne peut pas être static ou thread-local. La variable déclarée localement n’est pas nécessaire pour être constet peut muter.

  • Une fonction membre constexpr non-static n’est pas nécessaire pour être implicitement const.

constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

Conseil

Dans le débogueur de Visual Studio, lors du débogage d’une version Debug non optimisée, vous pouvez savoir si une fonction constexpr est évaluée au moment de la compilation en plaçant un point d’arrêt à l’intérieur de celle-ci. Si le point d'arrêt est atteint, la fonction a été appelée à l'exécution. Si ce n’est pas le cas, la fonction a été appelée au moment de la compilation.

Extern constexpr

L’option de compilateur /Zc :externConstexpr entraîne l’application du compilateur de liaison externe aux variables déclarées à l’aide de extern constexpr. Dans les versions antérieures de Visual Studio, soit par défaut, soit lorsque /Zc:externConstexpr- est spécifié, Visual Studio applique un lien interne aux variables constexpr même lorsque le mot-clé extern est utilisé. L’option /Zc:externConstexpr est disponible à partir de la mise à jour 15.6 de Visual Studio 2017 et est désactivée par défaut. L’option /permissive- n’active pas /Zc :externConstexpr.

Exemple

L’exemple suivant montre constexpr variables et des fonctions , ainsi qu’un type défini par l’utilisateur(-trice). Notez que, dans la dernière instruction dans main(), la constexprfonction membreGetValue() est un appel d’exécution, car la valeur n’est pas requise par le code au moment de la compilation.

// constexpr.cpp
// Compile with: cl /EHsc /W4 constexpr.cpp
#include <iostream>

using namespace std;

// Pass by value
constexpr float exp(float x, int n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp(x * x, n / 2) :
        exp(x * x, (n - 1) / 2) * x;
}

// Pass by reference
constexpr float exp2(const float& x, const int& n)
{
    return n == 0 ? 1 :
        n % 2 == 0 ? exp2(x * x, n / 2) :
        exp2(x * x, (n - 1) / 2) * x;
}

// Compile-time computation of array length
template<typename T, int N>
constexpr int length(const T(&)[N])
{
    return N;
}

// Recursive constexpr function
constexpr int fac(int n)
{
    return n == 1 ? 1 : n * fac(n - 1);
}

// User-defined type
class Foo
{
public:
    constexpr explicit Foo(int i) : _i(i) {}
    constexpr int GetValue() const
    {
        return _i;
    }
private:
    int _i;
};

int main()
{
    // foo is const:
    constexpr Foo foo(5);
    // foo = Foo(6); //Error!

    // Compile time:
    constexpr float x = exp(5, 3);
    constexpr float y { exp(2, 5) };
    constexpr int val = foo.GetValue();
    constexpr int f5 = fac(5);
    const int nums[] { 1, 2, 3, 4 };
    const int nums2[length(nums) * 2] { 1, 2, 3, 4, 5, 6, 7, 8 };

    // Run time:
    cout << "The value of foo is " << foo.GetValue() << endl;
}

Spécifications

Visual Studio 2015 ou version ultérieure.

Voir aussi

Déclarations et définitions
const