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
Loïc Joly
Loïc Joly writes:

| 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.

De manière générale, les membres de classe ont un linkage externe.


C'est ce point qui me gêne, d'autant plus qu'un membre static const de
classe n'appartient pas vraiment à la class. Quelle en est la motivation ?

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++).


Je suis d'accord avec ces arguments, et c'est le fait qu'ils ne
s'appliquent pas aux membres static const de classes pour lequel je ne
vois pas d'argument.


En l'occurence, le problème que j'ai avec ça est que je suis en train de
faire une macro qui, à partir de :

RICH_ENUM(Couleur, (Rouge)(Vert)(Bleu));

Génère du code dans le style (inspiré du papier n1719 de Sutter):

class Couleur
{
private:
enum MyEnum {Rouge_, Vert_, Bleu_, Invalid};
MyEnum myValue;
public:
static Couleur const Rouge, Vert, Bleu;
explicit Couleur(MyEnum val) : myValue( val ) { }
};

Couleur const Couleur::Rouge (Couleur::Rouge_);
Couleur const Couleur::Vert (Couleur::Vert_);
Couleur const Couleur::Bleu (Couleur::Bleu_);



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.

--
Loïc

Avatar
Horst Kraemer
Loïc Joly wrote:

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 ?


Parce que les significations de "static" dans

static int const i;

et dans

struct A
{
static int const i;
}

n'ont pas de relation entre elles. Stroustrup a préféré d'utiliser de
nouveau le mot clé "static" du langage C dans un autre contexte au
lieu d'inventer un nouveau mot clé.

static int const i;

est une variable qui n'est visible que dans le fichier dans lequel se
trouve la définition. Alors il y deux "::i". Un dans a.cpp et un dans
b.cpp avec deux définitions indépendantes pour chacun, tandis qu`il ne
peut y a voir qu`une seule définition pour le membre A::i, qui n'est
pas "static" dans le sens dans lequel ::i est "static".

--
Horst

--
Lâche pas la patate!

Avatar
Gabriel Dos Reis
Loïc Joly writes:

| 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.

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.

-- Gaby
Avatar
Gabriel Dos Reis
Horst Kraemer writes:

[...]

| > 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 ?
|
| Parce que les significations de "static" dans
|
| static int const i;
|
| et dans
|
| struct A
| {
| static int const i;
| }
|
| n'ont pas de relation entre elles. Stroustrup a préféré d'utiliser de
| nouveau le mot clé "static" du langage C dans un autre contexte au
| lieu d'inventer un nouveau mot clé.

En réalité, il a préféré utilisé « static » dans son sens originel
(une seule instance dans le programme).

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

| > Loïc Joly writes:
| > | 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.
| > De manière générale, les membres de classe ont un linkage externe.
|
| C'est ce point qui me gêne, d'autant plus qu'un membre static const de
| classe n'appartient pas vraiment à la class. Quelle en est la
| motivation ?

Je crois que les membres statiques de classe appartiennent à la classe :-)

| > 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++).
|
| Je suis d'accord avec ces arguments, et c'est le fait qu'ils ne
| s'appliquent pas aux membres static const de classes pour lequel je ne
| vois pas d'argument.

l'argument comme je l'ai dit plus haut est que les membres ont
un linkage extern et non interne -- pense au fait que les classes sont
incluses typiquement dans les en-têtes et à la règle ODR.

|
|
| En l'occurence, le problème que j'ai avec ça est que je suis en train
| de faire une macro qui, à partir de :
|
| RICH_ENUM(Couleur, (Rouge)(Vert)(Bleu));
|
| Génère du code dans le style (inspiré du papier n1719 de Sutter):
|
| class Couleur
| {
| private:
| enum MyEnum {Rouge_, Vert_, Bleu_, Invalid};
| MyEnum myValue;
| public:
| static Couleur const Rouge, Vert, Bleu;
| explicit Couleur(MyEnum val) : myValue( val ) { }
| };
|
| Couleur const Couleur::Rouge (Couleur::Rouge_);
| Couleur const Couleur::Vert (Couleur::Vert_);
| Couleur const Couleur::Bleu (Couleur::Bleu_);

Typiquement, ces définitions vont dans un .C.

| 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.

Hum. Si tu autorise que des membres de classe puissent avoir un
linkage interne, il faudra :
(1) donner une syntaxe,
(2) reformuler l'ODR.

Je n'ai de solution pour aucun des deux problèmes.

-- Gaby
Avatar
Jean-Marc Bourguet
Loïc Joly writes:

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"


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).

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
Jean-Marc Bourguet
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:

template <typename T>
class Couleur_Impl {
enum MyEnum {Rouge_, Vert_, Bleu_, Couleur_Impl_Invalid};
MyEnum myValue;
public:
static Couleur const Rouge, Vert, Bleu;
explicit Couleur(MyEnum val) : myValue( val ) { }
};


template <typename T>
Couleur_Impl const Couleur::Rouge (Couleur::Rouge_);
template <typename T>
Couleur_Impl const Couleur::Vert (Couleur::Vert_);
template <typename T>
Couleur_Impl const Couleur::Bleu (Couleur::Bleu_);

typedef Couleur_Impl<void> Couleur;

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
Gabriel Dos Reis
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.

-- Gaby
Avatar
Gabriel Dos Reis
Jean-Marc Bourguet writes:

| Loïc Joly writes:
|
| > 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"
|
| 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 » ;-)
Il aura (presque) toujours besoin de mettre la définition quelque
part, et je crois que c'est ça qui pose problème.

-- Gaby
Avatar
Loïc Joly

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 ?" ;)

--
Loïc

1 2 3