constexpr vs. static const: lequel préférer?

Pour définition des constantes de compilation de l'ensemble des types comme suit (à la fonction et la portée de classe), dont la syntaxe est la meilleure?

static const int kMagic = 64; // (1)
constexpr int kMagic = 64;    // (2)

(1) fonctionne aussi pour les compilateurs C++98/03, au lieu de (2) nécessite au moins C++11. Existe-il d'autres différences entre les deux? Est-ce que l'un ou l'autre devrait être préféré dans le code C++ moderne, et pourquoi?


Modifier

j'ai essayé ce code échantillon avec Godbolt's CE :

int main()
{
#define USE_STATIC_CONST
#ifdef USE_STATIC_CONST
  static const int kOk = 0;
  static const int kError = 1;
#else
  constexpr int kOk = 0;
  constexpr int kError = 1;
#endif
  return kOk;
}

et pour le cas static const c'est l'assemblage généré par GCC 6.2:

main::kOk:
        .zero   4
main::kError:
        .long   1
main:
        push    rbp
        mov     rbp, rsp
        mov     eax, 0
        pop     rbp
        ret

, d'autre part, pour constexpr c'est:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 0
        mov     DWORD PTR [rbp-8], 1
        mov     eax, 0
        pop     rbp
        ret

bien qu'à -O3 dans les deux cas j'obtienne le même assemblage (optimisé):

main:
        xor     eax, eax
        ret

EDIT #2

j'ai essayé ce code simple (en direct sur Ideone) :

#include <iostream>
using namespace std;

int main() {
    const int k1 = 10;
    constexpr int k2 = 2*k1;
    cout << k2 << 'n';
    return 0;
}

qui montre que const int k1 est évalué à temps de compilation , comme il est utilisé pour calculer constexpr int k2 .

Cependant, il semble y avoir un différents comportement double . J'ai créé une question séparée pour que ici .

25
demandé sur Community 2016-12-13 19:14:25

2 réponses

tant qu'il s'agit de déclarer des constantes de temps de compilation de scalar type entier ou enum, il n'y a absolument aucune différence entre l'utilisation de const ( static const dans la portée de la classe) ou constexpr .

notez que les compilateurs sont nécessaires pour supporter les objets static const int (déclarés avec des initialiseurs constants) dans des expressions constantes, ce qui signifie qu'ils n'ont pas d'autre choix que de traiter ces objets comme des constantes de temps de compilation. De plus, aussi longtemps que ces objets restent odr-unused, ils ne nécessitent aucune définition, ce qui prouve qu'ils ne seront pas utilisés comme valeurs de durée.

aussi, les règles de constant initialization empêchent les objets locaux static const int d'être initialisés dynamiquement, ce qui signifie qu'il n'y a pas de pénalité de performance pour déclarer ces objets localement. De plus, l'immunité de l'intégrale static s'oppose aux problèmes de commande de statique l'initialisation est une caractéristique très importante de la langue.

constexpr est une extension et une généralisation du concept qui a été initialement mis en œuvre en C++ à travers const avec un initialiseur constant. Pour les types entiers constexpr n'offre rien de plus que ce que const a déjà fait. constexpr effectue simplement un contrôle précoce de la" constance " de l'initialiseur. Cependant, on pourrait dire que constexpr est une caractéristique conçue spécifiquement pour ce faire, il s'adapte mieux stylistiquement.

10
répondu AnT 2016-12-14 15:15:21
La variable

constexpr est garantie d'avoir une valeur disponible au moment de la compilation. alors que static const members ou const variable pourrait signifier une valeur de temps de compilation ou une valeur d'exécution. Taper constexpr exprime votre intention d'une valeur temporelle de compilation d'une manière beaucoup plus explicite que const .

encore une chose, en C++17, constexpr les variables de membre de données statiques seront en ligne aussi. Cela signifie que vous pouvez omettre la définition hors ligne de static constexpr variables, mais pas static const .


comme une demande dans la section des commentaires, voici une explication plus détaillée au sujet de static const dans la portée de la fonction.

a static const variable à la portée de la fonction est à peu près la même, mais au lieu d'avoir une durée de stockage automatique, il a la durée de stockage statique. Que signifie, c'est en quelque sorte l'équivalent de déclarer la variable comme globale, mais uniquement accessible dans la fonction.

il est vrai qu'une variable static est initialisée au premier appel de la fonction, mais puisqu'elle est const aussi, le compilateur essayera d'aligner la valeur et d'optimiser complètement la variable. Ainsi, dans une fonction, si la valeur est connue au moment de la compilation pour cette variable, le compilateur le plus probable de l'optimiser.

cependant, si la valeur n'est pas connue au moment de la compilation pour un static const à la portée de la fonction, il pourrait silencieusement rendre votre fonction (un tout petit peu) plus lente, car il doit initialiser la valeur à l'exécution la première fois que la fonction est appelée. De plus, il doit vérifier si la valeur est initialisée chaque fois que la fonction est appelée.

C'est l'avantage d'une variable constexpr . Si la valeur n'est pas connue au moment de la compilation, c'est une erreur de compilation, pas un ralentissement fonction. Ensuite, si vous n'avez aucun moyen de déterminer la valeur de votre variable au moment de la compilation, le compilateur vous en informera et vous pourrez faire quelque chose à ce sujet.

24
répondu Guillaume Racicot 2017-08-04 11:44:21