initialiser variable constante dans le constructeur

Le
David Côme
Bonjour à tous.

Je recois en paramètre d'une classe une chaîne qui contient plusieurs
valeurs (des ints pour être précis).
Dans mon constructeur, je récupère ces variables via des *stringstream.
Jusque là, pas de problème.

La difficulté vient du fait que je souhaite ensuite affecter les valeurs
obtenues à des variables constantes
car les valeurs récupérées sont les valeurs que doivent avoir les
variables constantes.

Je ne peux donc pas donner de valeurs aux constantes dans la liste
d'initialisation puisque les valeurs ne sont pas encore connues.

Une idée ?

Merci.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Fabien LE LEZ
Le #2864851
On Sat, 12 Apr 2008 14:52:10 +0200, David Côme
Je ne peux donc pas donner de valeurs aux constantes dans la liste
d'initialisation puisque les valeurs ne sont pas encore connues.


class C
{
public:
C (std::string const&);
private:
int const a;
int const b;
};

C::C (std::string const& param)
: a (GetParametre (param, 1))
, b (GetParametre (param, 2))
{}



GetParametre (string const&, unsigned int n)
est bien sûr une fonction qui découpe la chaîne et renvoie le n-ième
entier.

David Côme
Le #2864841
On Sat, 12 Apr 2008 14:53:51 +0200, Fabien LE LEZ wrote:

On Sat, 12 Apr 2008 14:52:10 +0200, David Côme
Je ne peux donc pas donner de valeurs aux constantes dans la liste
d'initialisation puisque les valeurs ne sont pas encore connues.


class C
{
public:
C (std::string const&);
private:
int const a;
int const b;
};

C::C (std::string const& param)
: a (GetParametre (param, 1))
, b (GetParametre (param, 2))
{}



GetParametre (string const&, unsigned int n)
est bien sûr une fonction qui découpe la chaîne et renvoie le n-ième
entier.




Ok, merci.


James Kanze
Le #2931251
On 12 avr, 14:52, David Côme
Je recois en paramètre d'une classe une chaîne qui contient
plusieurs valeurs (des ints pour être précis). Dans mon
constructeur, je récupère ces variables via des *stringstream.
Jusque là, pas de problème.

La difficulté vient du fait que je souhaite ensuite affecter
les valeurs obtenues à des variables constantes car les
valeurs récupérées sont les valeurs que doivent avoir les
variables constantes.

Je ne peux donc pas donner de valeurs aux constantes dans la
liste d'initialisation puisque les valeurs ne sont pas encore
connues.

Une idée ?


Fabien a montré la solution classique, mais il faut signaler que
s'il s'agit de plusieurs valeurs, dans une seule chaîne de
caractères, la solution est loin d'être optimale, parce qu'il
faudrait récréer la istringstream pour chaque valeur, sautant
les valeurs qu'on ne recherche pas chaque fois. Dans ces cas-ci,
je me démande si le const vaut la peine. Const est surtout utile
au niveau des arguments d'une fonction ou des variables globales
(à cause des garanties qu'il promet), ou sinon quand il s'agit
d'une expression integrale constante (parce que certaines
constructions dans le langage l'exige). Ici, il s'agit
uniquement à des variables qui ne sont de toute façon pas
accessibles aux autres, et qui ne peuvent pas non plus servir
dans des expressions const. Du coup, le const se résume à une
petite promesse à toi-même.

Dans la pratique, je n'utilise pour ainsi dire jamais const sur
des variables locales ou membres privés.

--
James Kanze (GABI Software) email:
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

Pascal Bourguignon
Le #2971291
James Kanze
Fabien a montré la solution classique, mais il faut signaler que
s'il s'agit de plusieurs valeurs, dans une seule chaîne de
caractères, la solution est loin d'être optimale, parce qu'il
faudrait récréer la istringstream pour chaque valeur, sautant
les valeurs qu'on ne recherche pas chaque fois.


Quel manque d'imagination!

#include <ciso646>
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <exception>

class Error:public std::exception {
std::string message;
public:
Error(std::string const& aMessage):message(aMessage){};
~Error(void)throw(){};
const char* what(void){return(message.c_str());}
};

class C
{
public:
C(std::string const&);
inline int getA(void) const {return a;}
inline int getB(void) const {return b;}
private:
int const a;
int const b;
int getParameter(std::string const& arguments,unsigned int n);
};

C::C(std::string const& param)
: a(getParameter(param,1)),
b(getParameter(param,2))
{}


int C::getParameter(std::string const& arguments,unsigned int n){
typedef std::map<std::string,std::vector<int> > ParameterCache;
static ParameterCache cache;
ParameterCache::iterator parametersÊche.find(arguments);
if(parameters=Êche.end()){
std::istringstream in(arguments);
std::vector<int> parsedArgs;
while(not(in.eof())){
int argument;
in>>argument;
parsedArgs.push_back(argument);
}
cache[arguments]=parsedArgs;
parametersÊche.find(arguments);
}
if(parameters->second.size()<=n){
throw Error("Too few arguments");
}
return(parameters->second[n]);
}

int main(void){
C c0("0 1 2 3");
C c1("10 11 12 13");
std::cout<<"c0: "<<c0.getA()<<" "<<c0.getB()<<std::endl;
std::cout<<"c1: "<<c1.getA()<<" "<<c1.getB()<<std::endl;
return(0);
}

/*
-*- mode: compilation; default-directory: "~/src/miscellaneous/tests-c++/" -*-
Compilation started at Sun Apr 13 15:38:52

g++ -o const-member const-member.c++ && ./const-member
c0: 1 2
c1: 11 12

Compilation finished at Sun Apr 13 15:38:57
*/


--
__Pascal Bourguignon__ http://www.informatimago.com/

NEW GRAND UNIFIED THEORY DISCLAIMER: The manufacturer may
technically be entitled to claim that this product is
ten-dimensional. However, the consumer is reminded that this
confers no legal rights above and beyond those applicable to
three-dimensional objects, since the seven new dimensions are
"rolled up" into such a small "area" that they cannot be
detected.

James Kanze
Le #2976031
On 13 avr, 15:39, Pascal Bourguignon
James Kanze
Fabien a montré la solution classique, mais il faut signaler que
s'il s'agit de plusieurs valeurs, dans une seule chaîne de
caractères, la solution est loin d'être optimale, parce qu'il
faudrait récréer la istringstream pour chaque valeur, sautant
les valeurs qu'on ne recherche pas chaque fois.


Quel manque d'imagination!


Tu as oublié l'émoticon:-).

class C
{
public:
C(std::string const&);
inline int getA(void) const {return a;}
inline int getB(void) const {return b;}
private:
int const a;
int const b;
int getParameter(std::string const& arguments,unsigned int n);
};

C::C(std::string const& param)
: a(getParameter(param,1)),
b(getParameter(param,2))
{}

int C::getParameter(std::string const& arguments,unsigned int n){
typedef std::map<std::string,std::vector<int> > ParameterCache;
static ParameterCache cache;
ParameterCache::iterator parametersÊche.find(arguments);
if(parameters=Êche.end()){
std::istringstream in(arguments);
std::vector<int> parsedArgs;
while(not(in.eof())){


(Je sais que ta proposition est ironique, mais je tiens à
signaler en passant quand même qu'avec ce test, tu risques de
traiter un paramètre en trop, avec un comportement indéfini.)

int argument;
in>>argument;
parsedArgs.push_back(argument);
}
cache[arguments]=parsedArgs;
parametersÊche.find(arguments);
}
if(parameters->second.size()<=n){
throw Error("Too few arguments");
}
return(parameters->second[n]);
}


Avec une gestion d'erreurs correcte, des locks en plus si le
code est multi-thread, et assez de mémoire, effectivement, cette
solution pourrait marcher. Mais j'ai quand même comme une
impression que cette dernière considération va jouer contre elle
la plupart du temps.

int main(void){
C c0("0 1 2 3");
C c1("10 11 12 13");


Tu aurais dû essayer:

C c3( "1n" ) ;

Qui doit, je crois, provoque une erreur (mais qui ne le fait
probablement pas).

std::cout<<"c0: "<<c0.getA()<<" "<<c0.getB()<<std::endl;
std::cout<<"c1: "<<c1.getA()<<" "<<c1.getB()<<std::endl;
return(0);
}

/*
-*- mode: compilation; default-directory: "~/src/miscellaneous/tests-c++/" -*-
Compilation started at Sun Apr 13 15:38:52

g++ -o const-member const-member.c++ && ./const-member
c0: 1 2
c1: 11 12

Compilation finished at Sun Apr 13 15:38:57
*/


Et maintenant, avec une boucle :

std::string line ;
while ( std::getline( std::cin, line ) ) {
C c( line ) ;
std::cout << getA() << ' ' << c.getB() << std::endl ;
}

Avec en entrée, un fichier avec des milliards de lignes
différentes.

On pourrait imaginer quelque chose de ce genre, avec, disons :

class C
{
static std::istringstream parser ;

C( std::string const& init )
: a( getFirst( init ) )
, b( getNext() )
{
parser >> std::ws ;
if ( ! parser || parser.get() != EOF ) {
throw uneErrorDeSyntax ;
}
}

static int getFirst( std::string const& init )
{
parser.str( init ) ;
int result ;
init >> result ;
return result ;
}

static int getNext()
{
int result ;
init >> result ;
return result ;
}
// ...
} ;

C'est quand même assez fragile (puisqu'il dépend de l'ordre des
initialisations), et évidemment, dès qu'il y a des threads...
(On peut aussi le rendre thread-safe, mais c'est encore plus
exotique.)

--
James Kanze (GABI Software) email:
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


David Côme
Le #2976021
On Sun, 13 Apr 2008 15:39:49 +0200, Pascal Bourguignon

James Kanze
Fabien a montré la solution classique, mais il faut signaler que
s'il s'agit de plusieurs valeurs, dans une seule chaîne de
caractères, la solution est loin d'être optimale, parce qu'il
faudrait récréer la istringstream pour chaque valeur, sautant
les valeurs qu'on ne recherche pas chaque fois.


Quel manque d'imagination!

#include <ciso646>
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <exception>

class Error:public std::exception {
std::string message;
public:
Error(std::string const& aMessage):message(aMessage){};
~Error(void)throw(){};
const char* what(void){return(message.c_str());}
};

class C
{
public:
C(std::string const&);
inline int getA(void) const {return a;}
inline int getB(void) const {return b;}
private:
int const a;
int const b;
int getParameter(std::string const& arguments,unsigned int n);
};

C::C(std::string const& param)
: a(getParameter(param,1)),
b(getParameter(param,2))
{}


int C::getParameter(std::string const& arguments,unsigned int n){
typedef std::map<std::string,std::vector<int> > ParameterCache;
static ParameterCache cache;
ParameterCache::iterator parametersÊche.find(arguments);
if(parameters=Êche.end()){
std::istringstream in(arguments);
std::vector<int> parsedArgs;
while(not(in.eof())){
int argument;
in>>argument;
parsedArgs.push_back(argument);
}
cache[arguments]=parsedArgs;
parametersÊche.find(arguments);
}
if(parameters->second.size()<=n){
throw Error("Too few arguments");
}
return(parameters->second[n]);
}

int main(void){
C c0("0 1 2 3");
C c1("10 11 12 13");
std::cout<<"c0: "<<c0.getA()<<" "<<c0.getB()<<std::endl;
std::cout<<"c1: "<<c1.getA()<<" "<<c1.getB()<<std::endl;
return(0);
}

/*
-*- mode: compilation; default-directory:
"~/src/miscellaneous/tests-c++/" -*-
Compilation started at Sun Apr 13 15:38:52

g++ -o const-member const-member.c++ && ./const-member
c0: 1 2
c1: 11 12

Compilation finished at Sun Apr 13 15:38:57
*/




C'est une très belle solution mais après réflexion , j'ai l'impression que
je sort un tank pour
écraser 2 mouches.


Olivier Miakinen
Le #3334181

C'est une très belle solution mais après réflexion, j'ai l'impression que
je sors un tank pour écraser 2 mouches.


J'aime bien le « après réflexion ». ;-)

Publicité
Poster une réponse
Anonyme