Comment remplacer une macro par un équivalent plus C++

Le
kangs
Bonjour,

Pour simplifier du code j'utilise des macros, en C++ ce n'est par le
must
parait il.

Voici mon cas :

class A
{
public:
int indicateur1() const;
int indicateur2() const;
double indicateur3() const;
string indicateur4() const;

//
};

class FromBDD
: public A
{
public:
//
};

La class A contient environ une dizaine de variables, les données de A
sont
calculées et perdues en fin de programme.

La class FromBDD hérite de A et mémorise les indicateurs dans une BDD.

J'ai besoins de comparer chaque variable de A avec FromBDD et
d'indiquer les
variables qui ont changées visuellement.

Actuellement je fais en gros :
#define CMP( indicateur )
if { instA.indicateur() != fromBDD.indicateur() )
{
do_1( irow, icol );
}

for ( )
{
CMP( indicateur1 );
CMP( indicateur2 );

}

Est ce qu'il existe un moyen permettant de ce passer de la macro CMP
sans
avoir à copier/coller le code ?

Merci.
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
pjb
Le #20165571
kangs
Bonjour,

Pour simplifier du code j'utilise des macros, en C++ ce n'est par le
must
parait il.

Voici mon cas :

class A
{
public:
int indicateur1() const;
int indicateur2() const;
double indicateur3() const;
string indicateur4() const;

// ...
};

class FromBDD
: public A
{
public:
// ...
};

La class A contient environ une dizaine de variables, les données de A
sont
calculées et perdues en fin de programme.

La class FromBDD hérite de A et mémorise les indicateurs dans une BDD.

J'ai besoins de comparer chaque variable de A avec FromBDD et
d'indiquer les
variables qui ont changées visuellement.

Actuellement je fais en gros :
#define CMP( indicateur )



do{
if { instA.indicateur() != fromBDD.indicateur() )



{



do_1( irow, icol );



}



}while(0)


for ( ... )
{
CMP( indicateur1 );
CMP( indicateur2 );
...
}

Est ce qu'il existe un moyen permettant de ce passer de la macro CMP
sans
avoir à copier/coller le code ?



Personnellement, je ne trouve rien à redire sur l'usage d'une macro ici.


Ceci dit, on peut effectivement utiliser une fonction template:

template <class OBJECT,class GETTER> CMP(OBJECT& instance,OBJECT& fromBDD,GETTER getter,int irow,int icol){
if(instance->*getter()!=fromBDD->*getter()){
do_1(irow,icol);
}
}

for(...){
CMP(instA,fromBDD,&A::indicateur1,irow,icol);
CMP(instA,fromBDD,&A::indicateur2,irow,icol);
...
}



--
__Pascal Bourguignon__
Olivier Miakinen
Le #20167391
Le 17/09/2009 13:27, Pascal J. Bourguignon répondait à kangs :

Actuellement je fais en gros :
#define CMP( indicateur )



do{
if { instA.indicateur() != fromBDD.indicateur() )



{



do_1( irow, icol );



}



}while(0)



Oui aux « » de fin de ligne pour dire que la macro n'est pas finie, en
revanche le « do { ... } while(0) » ne me semble pas indispensable pour
une macro aussi simple et définie dans le même fichier. Ok, cela fait
des « ; » inutiles, mais est-ce que cela gênera le compilateur ?

À la limite, on pourrait même envisager d'écrire :
#define CMP(indicateur)
if (instA.indicateur() != fromBDD.indicateur())
do_1(irow, icol)

Note : il y avait une accolade ouvrante à la place d'une parenthèse
ouvrante, je suppose que c'était une erreur de recopie ici, erreur
absente du fichier source.

Personnellement, je ne trouve rien à redire sur l'usage d'une macro ici.



Moi non plus. Mon avis serait différent si la macro était dans un
fichier .h inclus, au lieu d'être définie dans le fichier même où
elle est utilisée.
pjb
Le #20168081
Olivier Miakinen
Oui aux « » de fin de ligne pour dire que la macro n'est pas finie, en
revanche le « do { ... } while(0) » ne me semble pas indispensable pour
une macro aussi simple et définie dans le même fichier. Ok, cela fait
des « ; » inutiles, mais est-ce que cela gênera le compilateur ?



D'accord. Je trouve juste que c'est une bonne habitude à prendre de
toujours mettre les macros "procedures" entre do{ et }while(0).

--
__Pascal Bourguignon__
kangs
Le #20171821
On 17 sep, 13:27, (Pascal J. Bourguignon)
wrote:
[...]
Ceci dit, on peut effectivement utiliser une fonction template:

template <class OBJECT,class GETTER> CMP(OBJECT& instance,OBJECT& fromBDD ,GETTER getter,int irow,int icol){
    if(instance->*getter()!=fromBDD->*getter()){
        do_1(irow,icol);
    }

}

for(...){
  CMP(instA,fromBDD,&A::indicateur1,irow,icol);
  CMP(instA,fromBDD,&A::indicateur2,irow,icol);
  ...

}



Merci pour la solution, mais je n'arrive pas à la mettre en oeuvre,
j'ai tenter de le faire sur un cas simple :

#include <iostream>

class A
{
public:
A( int i1, double i2 )
: ind1_( i1 )
,ind2_( i2 )
{}

int ind1() const { return ind1_; }
double ind2() const { return ind2_; }

private:
int ind1_;
double ind2_;
};

class B
: public A
{
public:
B( int i1, double i2 )
: A( i1, i2 )
{}
};

template< typename GETTER >
bool cmp( A const& a
,B const& b
,GETTER getter
)
{
if( a->*getter() != b->*getter() )
{
return true;
}
else
{
return false;
}
}

int main()
{
A a( 5, 12 );
B b( 5, 20 );

if ( cmp( a, b, &A::ind1 ) )
std::cout << "ind1 ==n";
else
std::cout << "ind1 !=n";

if ( cmp( a, b, &A::ind2 ) )
std::cout << "ind2 ==n";
else
std::cout << "ind2 !=n";

return 0;
}

Le compilateur me sort :
est.cpp: In function ‘bool cmp(const A&, const B&, GETTER) [with
GETTER = int (A::*)()const]’:
test.cpp:49: instantiated from here
test.cpp:34: erreur: must use ‘.*’ or ‘->*’ to call pointer-to-memb er
function in ‘getter (...)’
test.cpp:34: erreur: must use ‘.*’ or ‘->*’ to call pointer-to-memb er
function in ‘getter (...)’
test.cpp: In function ‘bool cmp(const A&, const B&, GETTER) [with
GETTER = double (A::*)()const]’:
test.cpp:54: instantiated from here
test.cpp:34: erreur: must use ‘.*’ or ‘->*’ to call pointer-to-memb er
function in ‘getter (...)’
test.cpp:34: erreur: must use ‘.*’ or ‘->*’ to call pointer-to-memb er
function in ‘getter (...)’

J'ai essayé de remplacer a->*getter() != b->*getter() par a.*getter() !
= b.*getter() mais ça ne change rien.

Qu'est ce qui cloche ?
pjb
Le #20172401
kangs
Le compilateur me sort :
est.cpp: In function ‘bool cmp(const A&, const B&, GETTER) [with
GETTER = int (A::*)()const]’:
test.cpp:49: instantiated from here
test.cpp:34: erreur: must use ‘.*’ or ‘->*†™ to call pointer-to-member
function in ‘getter (...)’

Qu'est ce qui cloche ?



Il faut des parentheses: if( (a->*getter)() != (b->*getter)() )

--
__Pascal Bourguignon__
pjb
Le #20172391
kangs
Le compilateur me sort :
est.cpp: In function ‘bool cmp(const A&, const B&, GETTER) [with
GETTER = int (A::*)()const]’:
test.cpp:49: instantiated from here
test.cpp:34: erreur: must use ‘.*’ or ‘->*†™ to call pointer-to-member
function in ‘getter (...)’

J'ai essayé de remplacer a->*getter() != b->*getter() par a.*gette r() !
= b.*getter() mais ça ne change rien.

Qu'est ce qui cloche ?



Il faut mettre des parentheses autour de (obj->*method) ou
(obj.*method), et puisqu'ici on n'a pas un pointeur mais une réfé rence
vers ces objets, il faut utiliser .*:

if( (a.*getter)() != (b.*getter)() )

SRC="/tmp/c.c++" ; EXE="c" ; g++ -g3 -ggdb3 -o ${EXE} ${SRC} && ./${E XE} && echo status = $?
ind1 !=
ind2 ==
status = 0

--
__Pascal Bourguignon__
kangs
Le #20172861
On 18 sep, 10:51, (Pascal J. Bourguignon)
wrote:
[...]
Il faut mettre des parentheses autour de (obj->*method) ou
(obj.*method), et puisqu'ici on n'a pas un pointeur mais une référenc e
vers ces objets, il faut utiliser .*:

        if( (a.*getter)() != (b.*getter)() )

SRC="/tmp/c.c++" ; EXE="c" ; g++  -g3 -ggdb3 -o ${EXE} ${SRC} &&  ./${EXE} && echo status = $?
ind1 !=
ind2 ==
status = 0



Merci.
kangs
Le #20172851
On 17 sep, 16:57, Olivier Miakinen
Le 17/09/2009 13:27, Pascal J. Bourguignon répondait à kangs :


[...]
Note : il y avait une accolade ouvrante à la place d'une parenthèse
ouvrante, je suppose que c'était une erreur de recopie ici, erreur
absente du fichier source.


Je n'ai pas copié j'ai juste voulu montrer l'idée...

> Personnellement, je ne trouve rien à redire sur l'usage d'une macro i ci.


Oui surtout que la solution template est plus /lourde/.

Moi non plus. Mon avis serait différent si la macro était dans un
fichier .h inclus, au lieu d'être définie dans le fichier même où
elle est utilisée.


En générale j'évite les macros, quand j'en utilise elles sont locales
à une fonction.
J'ai vraiment du mal a penser qu'un jour les macros n'existeront plus
en C++, je les trouve parfois bien pratiques.
pjb
Le #20172991
kangs
En générale j'évite les macros, quand j'en utilise elles sont locales
à une fonction.
J'ai vraiment du mal a penser qu'un jour les macros n'existeront plus
en C++, je les trouve parfois bien pratiques.



Si jamais ça arrive, tu pourras toujours passer à Lisp. ;-)



En passant, faire une macro "locale" avec cpp, est assez délicat; Le
mieux que l'on puisse faire, c'est utiliser #undef:

void MaClasse::maMethode(Other* other){
#undef MA_MACRO
#define MA_MACRO(X) (m##X=compute##X(#X,other->get_##X()))
MA_MACRO(nom);
MA_MACRO(age);
MA_MACRO(salaire);
#undef MA_MACRO
}


En Lisp, en plus des macros globales introduites par DEFMACRO, on a
des macros locales:

(defmethod ma-methode ((self ma-classe) other)
(macrolet ((ma-macro (field)
(setf (,field self) (,(intern (format nil "COMPUTE-~A" field))
,(string field)
(,(intern (format nil "GET-~A" field)) other)))))
(ma-macro nom)
(ma-macro age)
(ma-macro salaire)))



--
__Pascal Bourguignon__
pjb
Le #20173421
(Pascal J. Bourguignon) writes:
En passant, faire une macro "locale" avec cpp, est assez délicat; Le
mieux que l'on puisse faire, c'est utiliser #undef:

void MaClasse::maMethode(Other* other){
#undef MA_MACRO
#define MA_MACRO(X) (m##X=compute##X(#X,other->get_##X()))
MA_MACRO(nom);
MA_MACRO(age);
MA_MACRO(salaire);
#undef MA_MACRO
}


En Lisp, en plus des macros globales introduites par DEFMACRO, on a
des macros locales:

(defmethod ma-methode ((self ma-classe) other)
(macrolet ((ma-macro (field)
(setf (,field self) (,(intern (format nil "COMPUTE-~A" field))


`
Il manque une backquote devant (setf ; désolé pour la confusion.

--
__Pascal Bourguignon__
Publicité
Poster une réponse
Anonyme