constexpr (C++)

Le mot clé constexpr a été introduit en C++11 et amélioré en C++14. Cela signifie constune expression dente. Comme const, il peut être appliqué à des variables : une erreur du compilateur est déclenchée quand un code tente de modify la valeur. Contrairement constà , constexpr peut également être appliqué aux fonctions et aux ructoraux de classe const. constexpr indique que la valeur ou la valeur de retour est constdente et, dans la cas possible, est calculée au moment de la compilation.

Une constexpr valeur intégrale peut être utilisée partout où un const entier est requis, par exemple dans les arguments de modèle et les déclarations de tableau. Et lorsqu’une valeur est calculée au moment de la compilation au lieu de l’exécution, elle permet à votre programme d’exécuter plus rapidement et d’utiliser moins de mémoire.

Pour limiter la complexité des calculs d’ant au moment constde la compilation et leur impact potentiel sur le temps de compilation, la norme C++14 exige que les types d’expressions constant soient des types littérals.

Syntaxe

constexprident de typelittéral ier=constant-expression ;if
constexprident de typelittéral ier{ant-expressionconst} ;if
constexprident de typelittéral ier(params) ;if
constexprctor(params) ;

Paramètres

params
Un ou plusieurs paramètres, dont chacun doit être un type littéral et doit lui-même être une constexpression dent.

Valeur retournée

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

Variables constexpr

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

  • Une variable peut être déclarée avec constexpr, lorsqu’elle a un type littéral et est initialisée. Si l’initialisation est effectuée par unforconst ructoreur, le constructor 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 constexpression ant et toutes les conversions implicites appelées pendant l’initialisation sont également constdes expressions dent.

  • Toutes les déclarations d’une variable ou d’une constexpr fonction doivent avoir la constexpr spécificationifplus grande.

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 constexpr fonction est une fonction dont la valeur de retour est computable au moment de la compilation lorsque le code le nécessite. Le code consommant nécessite la valeur de retour au moment de la compilation pour initialiser une constexpr variable ou pour fournir un argument de modèle non de type. Lorsque ses arguments sont constexpr des valeurs, une constexpr fonction produit une fourmi au moment constde la compilation. Lorsqu’elle est appelée avec des arguments nonconstexpr arguments ou si sa valeur n’est pas requise au moment de la compilation, elle produit une valeur au moment de l’exécution comme une fonction régulière. (Ce comportement double vous permet d’avoir à écrire constexpr et non desconstexpr versions de la même fonction.)

Une constexpr fonction ou constun ructorateur est implicitement inline.

Les règles suivantes s’appliquent aux constexpr fonctions :

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

  • Une constexpr fonction peut être récursive.

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

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

  • Le corps ne peut contenir aucune goto instruction ni try bloc.

  • Une spécialisation explicite d’un modèle non-modèleconstexpr peut être déclarée comme constexprsuit :

  • Une spécialisation explicite d’un constexpr modèle n’a pas non plus besoin d’être constexpr:

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

  • Il peut contenir et des instructions, ainsi que toutes les instructions de bouclage, y comprisfor, basées sur fordes plages, whileet do-while.ifswitch

  • 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 constet peut muter.

  • Une constexpr fonction non membrestatic 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 Visual Studio, lors du débogage d’une build de débogage non optimisée, vous pouvez indiquer si une constexpr fonction est évaluée au moment de la compilation en y plaçant un point d’arrêt. Si le point d'arrêt est atteint, la fonction a été appelée à l'exécution. Sinon, la fonction a été appelée au moment de la compilation.

Extern constexpr

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

Exemple

L’exemple suivant montre des constexpr variables, des fonctions et un type défini par l’utilisateur. Dans la dernière instruction dans main(), la constexpr fonction GetValue() membre est un appel au moment de l’exécution, car la valeur n’est pas requise pour être connue 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