web-dev-qa-db-fra.com

Confusion concernant la déclaration et la définition des membres de données statiques const

Scott Meyers écrit dans Effective Modern C++, Item 30 page 210, qu'il y a

pas besoin de définir l'intégrale static const membres de données dans les classes; les déclarations seules suffisent,

alors l'exemple de code est

class Widget {
  public:
    static const std::size_t MinVals = 28; // MinVals' declaration;
    ...
};
...                                        // no defn. for MinVals
std::vector<int> widgetData;
widgetData.reserve(Widget::MinVals);       // use of MinVals

J'étais convaincu que static const std::size_t MinVals = 28; est une déclaration et aussi une définition, car elle donne une valeur à MinVals, mais les commentaires semblent prétendre que ce n'est qu'une déclaration; le deuxième commentaire prétend en fait qu'il n'y a pas de définition. Le texte après le code lit en effet

MinVals n'a pas de définition.

Ce qui confirme que static const std::size_t MinVals = 28; n'est pas une définition, donc je suis un peu confus.

cppreference ne m'aide pas beaucoup (mon gras-italique):

Si un membre de données static de type intégral ou énumération est déclaré const (et non volatile), il peut être initialisé avec un initialiseur dans lequel chaque expression est une expression constante, juste à l'intérieur de la définition de classe:

struct X
{
    const static int n = 1;
    const static int m{2}; // since C++11
    const static int k;
};
const int X::k = 3;

mais les deux premières lignes de la classe me regardent les définitions.

Il en va de même pour un exemple suivant sur cppreference:

struct X {
    static const int n = 1;
    static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n;             // … so a definition is necessary
constexpr int X::m;         // … (except for X::m in C++17)

où j'aurais dit static const int n = 1; est une définition, mais ce n'est pas le cas, basée sur l'avant-dernier commentaire.

En regardant ceci Draft Standard , il semble que votre exemple tombe dans une zone grise. Bien qu'il n'y ait pas explicite mention de lignes telles que:

    static const std::size_t MinVals = 28;

Il y a un exemple donné qui est très similaire:

6.1 Déclarations et définitions
...
2 Une déclaration est une définition sauf si
...
2.3 - il déclare un membre de données statiques non en ligne dans une définition de classe
...
Exemple: Tous les éléments suivants sauf un sont des définitions:

int a; // définit un
extern const int c = 1; // définit c
...

Le deuxième exemple est close à votre code, mais avec une différence significative dans le qualificatif extern. Notez également que ce qui précède indique qu'une déclaration est (par défaut) également une définition sauf si l'une des conditions énumérées s'applique; Je dirais (même si je ne suis pas un avocat de la langue) qu'aucune de ces conditions n'est remplie exactement dans votre cas, donc votre déclaration est également une définition.

REMARQUE: Le document lié n'est qu'un standard draft; assurez-vous de lire la "clause de non-responsabilité" donnée au bas de sa première page!

3
Adrian Mole

From The Standard Chapitre "12.2.3.2 Membres de données statiques":

Le membre doit toujours être défini dans une portée d'espace de noms s'il est utilisé par odr dans le programme et la définition de portée d'espace de noms ne doit pas contenir d'initialiseur.

En l'utilisant, il doit être défini.

0
Dragan