Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[CONTAINERS] constructeur avec arguments dans une declaration de classe

7 réponses
Avatar
gornack
Bonjour

J'ai un probleme avec les constructeurs de la classe bitset de la STL
(mais le probleme existe apparemment avec tous les containers de la
STL).
Pour rappel, la classe bitset est une classe templatee par un entier
qui represente la taille du champ de bits cree.
Le constructeur par default (sans argument) marche parfaitement.
Le probleme se corse quand j'essaie d'utiliser un constructeur prenant
en parametre un long qui specifie la valeur initiale du champs de bits.
Par exemple:

std::bitset<32> bs(42);

est censee creer un champs de bits de 32 bits, dont le nom est "bs" et
dont la valeur initiale est 42 (101010 en binaire)
cela marche tres bien dans une fonction main de test par exemple.
Mais lorsque j'essaie de declarer un membre de type bitset dans une
classe avec ce meme constructeur, g++ (v4.1.0) m'annonce une erreur :

error: expected identifier before numeric constant
error: expected ',' or '...' before numeric constant

ces deux erreurs ont lieu a la ligne du constructeur en question
un petit exemple de code qui fait cette erreur pour illustrer mon
probleme :

---------- file test.hh
#include <bitset>

class MyClass
{
public:
std::bitset<32> bs(42);
};
---------- end file test.hh

voila ces quelques lignes ne compilent absolument pas et me sortent
l'erreur precedemment citee
alors que le code suivant compile parfaitement :

---------- file test.cc
#include <bitset>
#include <iostream>

int main()
{
std::bitset<32> bs(42);
std::cout << bs << std::endl;
return 0;
}
--------- end file test.cc

Savez vous ce qu'il se passe et comment y remedier (il y a bien des
moyens tels que specifier la valeur de bs dans le constructeur de
MyClass, mais je n'ai pas encore trouve le moyen de remedier a ce
probleme si notre variable est declaree const)
Merci d'avance

--
Mike
KameHouse Prod.

7 réponses

Avatar
Sylvain
wrote on 11/07/2006 01:06:

class MyClass {
public:
std::bitset<32> bs(42);
};


vous initialisez les champs non constants comme cela vous ?
(c'est pas du Java !)

Savez vous ce qu'il se passe et comment y remedier (il y a bien des
moyens tels que specifier la valeur de bs dans le constructeur de
MyClass, mais je n'ai pas encore trouve le moyen de remedier a ce
probleme si notre variable est declaree const)


ben voila ! tout est dit, c'est bien comme cela que ça marche (*)
(template ou non).

(*):
MyClass::MyClass() : bs(42) {}
ou
MyClass::MyClass() { bs = 42; }

Sylvain.

Avatar
Sylvain
wrote on 11/07/2006 01:06:

mais je n'ai pas encore trouve le moyen de remedier a ce
probleme si notre variable est declaree const)


j'avais lu 'sauf si elle est const' ...

la règle est quasi la même: la définition est distincte de la
déclaration, soit:

class MyClass {
public:
static const std::bitset<32> bs;
};

puis:

const std::bitset<32> MyClass::bs(42);

Sylvain.

Avatar
gornack

wrote on 11/07/2006 01:06:

mais je n'ai pas encore trouve le moyen de remedier a ce
probleme si notre variable est declaree const)


j'avais lu 'sauf si elle est const' ...

la règle est quasi la même: la définition est distincte de la
déclaration, soit:

class MyClass {
public:
static const std::bitset<32> bs;
};

puis:

const std::bitset<32> MyClass::bs(42);

Sylvain.


Je vous remercie pour cette reponse aussi rapide que precise.
--
Mike
KameHouse Prod.


Avatar
Sylvain
wrote on 11/07/2006 01:06:

je vous ai répondu sans détailler la source de l'erreur.

dans les 2 écritures:

class MyClass {
std::bitset<32> bs(42);
};


et

int main() {
std::bitset<32> bs(42);
}


il faut comprendre que la première n'est rien d'autre qu'une définition
-- on introduit un champ nommé, typé, mais il n'existe pas par cette
seule ligne (il existera avec l'instance complète lorsqu'un MyClass sera
déclaré).

à l'inverse, la déclaration dans une fonction (ou comme variable
globale) définit bien une variable de type bitset<32>, cette création
attend donc l'invocation d'un constructeur, soit implicite sans
paramètre avec l'écriture "std::bitset<32> bs;" soit explicite paramètré
avec une écriture comme soumisse.

je comparais l'écriture avec Java car pour celui-ci l'introduction d'une
variable définie bien celle-ci et les écritures ci-après sont toutes
valides:

class MyClass {
BitSet bs1;
BitSet bs2 = null;
BitSet bs3 = new BitSet(32);
};

C++ brouille un peu les pistes car il permet la définition immédiate
(dite inline) d'une méthode, eg.

class MyClass {
...
std::bitset<32>& getBitSet() { return bs; }
};

ceci n'est toutefois qu'un raccourci d'écriture, cette expression ne
créé aucune instance immédiate et il faudra bien déclarer une telle
variable pour invoquer cette méthode.

Sylvain.

Avatar
kanze
Sylvain wrote:
wrote on 11/07/2006 01:06:

je vous ai répondu sans détailler la source de l'erreur.

dans les 2 écritures:

class MyClass {
std::bitset<32> bs(42);
};


et

int main() {
std::bitset<32> bs(42);
}



Il s'agit ici d'un détail de vocabulaire, mais puisque
l'explication se base sur une particularité du vocabulaire
propre à C++...

il faut comprendre que la première n'est rien d'autre qu'une
définition -- on introduit un champ nommé, typé, mais il
n'existe pas par cette seule ligne (il existera avec
l'instance complète lorsqu'un MyClass sera déclaré).

à l'inverse, la déclaration dans une fonction (ou comme
variable globale) définit bien une variable de type
bitset<32>, cette création attend donc l'invocation d'un
constructeur, soit implicite sans paramètre avec l'écriture
"std::bitset<32> bs;" soit explicite paramètré avec une
écriture comme soumisse.


Le vocabulaire du C++ distingue très nettement entre
« définition » et « déclaration ». Même si toute définition
est aussi une déclaration, c'est mieux d'être précise. Les deux
termes ne sont pas équivalents, et ne s'utilisent pas d'une
façon interchangeable. (Sinon, ton explication est tout à fait
correcte.)

je comparais l'écriture avec Java car pour celui-ci
l'introduction d'une variable définie bien celle-ci et les
écritures ci-après sont toutes valides:

class MyClass {
BitSet bs1;
BitSet bs2 = null;
BitSet bs3 = new BitSet(32);
};


La différence entre le Java et le C++ ici n'est pas énorme.
C'est pûrement une question d'écriture ; les initialisations
des variables membres (non-statiques) font en fait partie du
constructeur, et sont exécuter lors de l'exécution du
constructeur, exactement comme si on les avait écrit dans le
constructeur.

C++ brouille un peu les pistes car il permet la définition
immédiate (dite inline) d'une méthode, eg.

class MyClass {
...
std::bitset<32>& getBitSet() { return bs; }
};


Ce que Java exige. Ici, ce n'est pas tellement C++ qui brouille
les pistes, mais Java, en permettant l'écriture d'une partie du
constructeur en dehors du constructeur. Et évidemment, une des
grandes faiblesses de Java, c'est aussi qu'il ne permet pas de
mettre les détails de l'implémentation (comme les corps de
fonction) dans un fichier à part.

ceci n'est toutefois qu'un raccourci d'écriture, cette
expression ne créé aucune instance immédiate et il faudra bien
déclarer une telle variable pour invoquer cette méthode.


De même qu'en Java.

--
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
Sylvain wrote:
wrote on 11/07/2006 01:06:

class MyClass {
public:
std::bitset<32> bs(42);
};


vous initialisez les champs non constants comme cela vous ?
(c'est pas du Java !)


Constantes ou non, ça ne marche pas. En fait, pour que la
spécification d'une initialisation soit permise dans la classe,
il faut que 1) le membre soit statique, 2) il soit déclaré
const, et 3) il ait un type entier ou d'énumération. Il s'agit
vraiement d'un cas spécial.

Savez vous ce qu'il se passe et comment y remedier (il y a
bien des moyens tels que specifier la valeur de bs dans le
constructeur de MyClass, mais je n'ai pas encore trouve le
moyen de remedier a ce probleme si notre variable est
declaree const)


ben voila ! tout est dit, c'est bien comme cela que ça marche (*)
(template ou non).

(*):
MyClass::MyClass() : bs(42) {}
ou
MyClass::MyClass() { bs = 42; }


Avec une forte préférence pour le premier (qui est le seul qui
marche si bs est const).

--
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
Sylvain wrote:
wrote on 11/07/2006 01:06:

mais je n'ai pas encore trouve le moyen de remedier a ce
probleme si notre variable est declaree const)


j'avais lu 'sauf si elle est const' ...

la règle est quasi la même: la définition est distincte de la
déclaration, soit:

class MyClass {
public:
static const std::bitset<32> bs;
};

puis:

const std::bitset<32> MyClass::bs(42);


Attention. Ce n'est pas la même chose. Ici, tu as déclaré le
membre statique. (Évidemment, si il est const, et toujours
initialisé avec la même valeur, on pourrait préférer qu'il soit
statique. Au moins que ça pose de problèmes de l'ordre
d'initialisation.)

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