OVH Cloud OVH Cloud

static const

30 réponses
Avatar
Loïc Joly
Bonjour,

Je me demande pourquoi dans le code suivant :

// a.h

int const i = 42;

class A { static int const i;};

int const A::i = 42;

// a.cpp
#include "a.h"

// b.cpp
#include "a.h"


Pourquoi n'y a-t-il pas de problèmes de définition multiple pour i alors
qu'il y en a pour A::i ?

Je sais que c'est ce que demande le standard :
Static data members of a class in namespace scope have external linkage
(3.5). A local class shall not have static data members.

Mais je ne comprends pas vraiment la motivation de cette différence.

--
Loïc

10 réponses

1 2 3
Avatar
Jean-Marc Bourguet
Gabriel Dos Reis writes:

Jean-Marc Bourguet writes:

| Loïc Joly writes:
|
| > Et qu'à cause du problème de linkage externe, je me trouve obligé de
| > demander à l'utilisateur de saisir dans le .h :
| > DECLARE_RICH_ENUM(Couleur, (Rouge)(Vert)(Bleu));
| >
| > Et dans un .cpp :
| > IMPLEMENT_RICH_ENUM(Couleur, (Rouge)(Vert)(Bleu));
| >
| > Ce qui fait une lourdeur et une duplication de code
| > qui me gênent, et pour lesquelles je n'ai pas trouvé
| > d'alternative.
|
| Si tu insistes réellement, tu peux abuser des templates:

ou définir les couleurs dans un namespace.


anonyme je suppose. Ça marche tant qu'on ne prend pas les
adresses des constantes; relativement raisonnable comme
contrainte dans ce contexte.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
James Kanze
Gabriel Dos Reis wrote:
Loïc Joly writes:


| Je me demande pourquoi dans le code suivant :


| // a.h


| int const i = 42;


| class A { static int const i;};


| int const A::i = 42;


| // a.cpp
| #include "a.h"


| // b.cpp
| #include "a.h"


| Pourquoi n'y a-t-il pas de problèmes de définition multiple
| pour i alors qu'il y en a pour A::i ?


| Je sais que c'est ce que demande le standard :
| Static data members of a class in namespace scope have
| external linkage (3.5). A local class shall not have static
| data members.


| Mais je ne comprends pas vraiment la motivation de cette
| différence.


De manière générale, les membres de classe ont un linkage
externe. En ce qui concerne const à portée de namespace, il y
a une discussion dans D&E que j'ai citée plusieurs fois dans
ce groupe (à propos de la différence de "const" entre C et
C++). Page 90:


[...] In the meantime, I had experimented further with const in C
with Classes and found that const was a useful alternative to macros
for representing constants only if global consts were implicitly
local to their compilation unit. Only in that case could the
compiler easily deduce that their value really didn't change.
Knowing that allows us to use simple consts in constant expressions
and to avoid allocating space for such constants. C did not adopt
this rule.
[...] This makes consts far less useful in C than in C++ and leaves
C dependent on the preprocessor while C++ programmers can use
properly typed and scoped consts.


Ce qui n'explique pas tout, loin de là.

D'abord, évidemment, ce qui rend const moins utile en C, c'est
le fait qu'on ne peut pas s'en servir dans une expression
entière const. Indépendamment de linkage et al.

Pour la reste, si c'est évident qu'une const avec linkage
externe, qui n'est initialisée que dans une seule unité de
traduction, ne peut pas vraiment remplacé les #define, il me
semble bien moins évident que c'est un problème réel : il suffit
de déclarer le const static, et ça marche. Et si on a besoin
d'une règle spéciale, permettre une initialisation dans
plusieurs unités de compilation fait bien l'affaire aussi ; en
fin de compte, c'est ce qui se passe aujourd'hui avec des
templates.

En fin de compte, la règle que le const implique une absense de
linkage est plutôt une manque d'orthogonalité gratuite.

--
James Kanze mailto:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

Avatar
Gabriel Dos Reis
Jean-Marc Bourguet writes:

| Gabriel Dos Reis writes:
|
| > Jean-Marc Bourguet writes:
| >
| > | Loïc Joly writes:
| > |
| > | > Et qu'à cause du problème de linkage externe, je me trouve obligé de
| > | > demander à l'utilisateur de saisir dans le .h :
| > | > DECLARE_RICH_ENUM(Couleur, (Rouge)(Vert)(Bleu));
| > | >
| > | > Et dans un .cpp :
| > | > IMPLEMENT_RICH_ENUM(Couleur, (Rouge)(Vert)(Bleu));
| > | >
| > | > Ce qui fait une lourdeur et une duplication de code
| > | > qui me gênent, et pour lesquelles je n'ai pas trouvé
| > | > d'alternative.
| > |
| > | Si tu insistes réellement, tu peux abuser des templates:
| >
| > ou définir les couleurs dans un namespace.
|
| anonyme je suppose.

Pas vraiment... Dans un namespace ordinaire, je pensais.

| Ça marche tant qu'on ne prend pas les
| adresses des constantes; relativement raisonnable comme
| contrainte dans ce contexte.

Cette contrainte ne s'applique que pour la solution avec les classes,
et pas aux namespaces.

-- Gaby
Avatar
Gabriel Dos Reis
Loïc Joly writes:

| > Si tu insistes réellement, tu peux abuser des templates:
|
| Merci, cet abus me donne le résultat que j'escomptais...
|
| La seule question qui me reste, c'est "oserais-je admettre un jour que
| j'ai écrit ce genre de code ?" ;)

non, je présume ;-)

-- Gaby
Avatar
Gabriel Dos Reis
James Kanze writes:

[...]

| Ce qui n'explique pas tout, loin de là.

mais, j'avais anticipé que tu allais completer.

|
| D'abord, évidemment, ce qui rend const moins utile en C, c'est
| le fait qu'on ne peut pas s'en servir dans une expression
| entière const. Indépendamment de linkage et al.
|
| Pour la reste, si c'est évident qu'une const avec linkage
| externe, qui n'est initialisée que dans une seule unité de
| traduction, ne peut pas vraiment remplacé les #define, il me
| semble bien moins évident que c'est un problème réel : il suffit
| de déclarer le const static, et ça marche.

Avec beaucoup de lourdeur syntaxtique, on peut arriver à beaucoup de
choses. Après on peut se demander si les cas majoritaires doivent
nécessiter la même lourdeur que les autres.

Enfin, comme je l'ai déjà fait observé Ni BS ni DMR n'ont jamais aimé
ou envisagé que « static » devrait avoir quoi que ce soit vace
« linkage > -- en réalité, aucun des deux n'aime ce concept.

[...]

| En fin de compte, la règle que le const implique une absense de
| linkage est plutôt une manque d'orthogonalité gratuite.

Donc, je ne vois pas de quoi tu te plains ;-)

-- Gaby
Avatar
kanze
Gabriel Dos Reis wrote:
James Kanze writes:

[...]

| Ce qui n'explique pas tout, loin de là.

mais, j'avais anticipé que tu allais completer.


:-)

| D'abord, évidemment, ce qui rend const moins utile en C,
| c'est le fait qu'on ne peut pas s'en servir dans une
| expression entière const. Indépendamment de linkage et al.

| Pour la reste, si c'est évident qu'une const avec linkage
| externe, qui n'est initialisée que dans une seule unité de
| traduction, ne peut pas vraiment remplacé les #define, il me
| semble bien moins évident que c'est un problème réel : il
| suffit de déclarer le const static, et ça marche.

Avec beaucoup de lourdeur syntaxtique, on peut arriver à
beaucoup de choses.


Un static de plus dans la declaration. Ce n'est pas vraiment
beaucoup de lourdeur.

Après on peut se demander si les cas majoritaires doivent
nécessiter la même lourdeur que les autres.


C-à-d qu'on doit rendre les utilisations majoritaires
systèmatiquement les plus courtes, même au prix de
l'orthogonalité.

C'est un argument. Ici, je ne suis pas trop convaincu, parce que
je trouve la différence assez minime, mais ce n'est évidemment
qu'une opinion -- c'est largement une question de goût. (Note
que dans les cas plus extrème, j'accepterais l'argument sans
problème. Je ne suis pas doctrinaire là-dessus. C'est justement
qu'éviter de taper 7 caractères ne me semble pas assez de
justification.)

Enfin, comme je l'ai déjà fait observé Ni BS ni DMR n'ont
jamais aimé ou envisagé que « static » devrait avoir quoi que
ce soit vace « linkage > -- en réalité, aucun des deux n'aime
ce concept.


Qu'on ne l'aime pas, je conçois bien -- avec plus de vingt ans
d'expérience en C, puis en C++, j'y suis habité, mais je
reconnais qu'il m'a un peu choqué aussi, quand j'apprenais le C.
(Encore que ce qui m'a choqué le plus, c'est qu'une variable
soit « publique » par défaut, et qu'il fallait ajouter quelque
chose pour le rendre « privée ». Pour revenir à ton argument
ci-dessus -- la forme non-marquée devait être la plus simple.)

N'empèche que cette innovation-là, tu ne peux pas la mettre sur
le dos du comité C. C'était bien présent dans les premiers C que
j'ai vu. Que DMR ne l'aime pas, je veux bien, mais c'est quand
même lui ou l'un de ses collègues qui l'ont introduit dans le
langage.

Maintenant, si BS avait changé le défaut partout, c-à-d qu'une
déclaration à la portée de fichier (alors) n'avait pas de
linkage, sauf si on le déclarer extern ou global ou quelque
chose du genre, je n'aurais rien à dire. C'est simplement la
manque d'orthogonalité qui me gène.

Et honnêtement, c'est une gène mineur. Si je ne pouvais changer
qu'une chose dans le C++, il y a bien de chose qui viendrait
avant.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
kanze
Gabriel Dos Reis wrote:
Jean-Marc Bourguet writes:

| Loïc Joly writes:

| > Je me demande pourquoi dans le code suivant :

| > // a.h

| > int const i = 42;

| > class A { static int const i;};

| > int const A::i = 42;

| > // a.cpp
| > #include "a.h"

| > // b.cpp
| > #include "a.h"

| En passant je rappelle que

| class A { static int const i = 42;};

| ne poserait pas de problème (mais n'est possible que pour
| les entiers).

mais c'est un « misfeature » ;-)


J'en conviens ; c'est même plutôt affreux, quand on y pense.
Mais il réponds à un besoin réel. Comment ferais-tu à déclarer
une constante à portée de la classe, qui a le bon type, et qui
est aussi disponible dans la définition de la classe ?

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Gabriel Dos Reis
writes:

| Gabriel Dos Reis wrote:
| > Jean-Marc Bourguet writes:
|
| > | Loïc Joly writes:
|
| > | > Je me demande pourquoi dans le code suivant :
|
| > | > // a.h
|
| > | > int const i = 42;
|
| > | > class A { static int const i;};
|
| > | > int const A::i = 42;
|
| > | > // a.cpp
| > | > #include "a.h"
|
| > | > // b.cpp
| > | > #include "a.h"
|
| > | En passant je rappelle que
|
| > | class A { static int const i = 42;};
|
| > | ne poserait pas de problème (mais n'est possible que pour
| > | les entiers).
|
| > mais c'est un « misfeature » ;-)
|
| J'en conviens ; c'est même plutôt affreux, quand on y pense.
| Mais il réponds à un besoin réel. Comment ferais-tu à déclarer
| une constante à portée de la classe, qui a le bon type, et qui
| est aussi disponible dans la définition de la classe ?

Peut-être que le besoin est réel, mais ça marche pas.
(1) il faut quand même donner la définition quelque part dans le
programme
(2) on ne peut le faire que si la variable est const ;
(3) en plus il faut que ce soit de type entier.

-- Gaby
Avatar
kanze
Gabriel Dos Reis wrote:
writes:

| Gabriel Dos Reis wrote:
| > Jean-Marc Bourguet writes:

| > | Loïc Joly writes:

| > | > Je me demande pourquoi dans le code suivant :

| > | > // a.h

| > | > int const i = 42;

| > | > class A { static int const i;};

| > | > int const A::i = 42;

| > | > // a.cpp
| > | > #include "a.h"

| > | > // b.cpp
| > | > #include "a.h"

| > | En passant je rappelle que

| > | class A { static int const i = 42;};

| > | ne poserait pas de problème (mais n'est possible que
| > | pour les entiers).

| > mais c'est un « misfeature » ;-)

| J'en conviens ; c'est même plutôt affreux, quand on y pense.
| Mais il réponds à un besoin réel. Comment ferais-tu à
| déclarer une constante à portée de la classe, qui a le bon
| type, et qui est aussi disponible dans la définition de la
| classe ?

Peut-être que le besoin est réel, mais ça marche pas.
(1) il faut quand même donner la définition quelque part dans le
programme


Et alors ? Je n'ai jamais dit que c'était élégant. Je n'aime
pas, mais dans la mesure qu'on ne m'offre rien d'autre.

(2) on ne peut le faire que si la variable est const ;


Vue que le besoin, c'est bien de declarer une constante, je ne
vois pas où c'est un problème.

(3) en plus il faut que ce soit de type entier.


C'est pire que ton point 1), j'en conviens. Mais la réponse en
est la même : dans la mesure où on ne m'offre rien d'autre...

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Michel Michaud
Dans le message ,
Et alors ? Je n'ai jamais dit que c'était élégant. Je n'aime
pas, mais dans la mesure qu'on ne m'offre rien d'autre.
[...]

(3) en plus il faut que ce soit de type entier.


C'est pire que ton point 1), j'en conviens. Mais la réponse en
est la même : dans la mesure où on ne m'offre rien d'autre...


Oui, on t'offre et on a depuis longtemps le truc de l'enum.
Qui évite d'avoir à faire une définition.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


1 2 3