J'ai une classe Point2D contenant deux doubles
x et y et un constructeur, puis une classe Poly2D
contenant un deque<Point2D>. Le problème se
pose avec le constructeur de Poly2D qui admet
une liste variable d'arguments.
Voici son code:
va_start(vl,premier);
_pol.push_back(premier);
while (suivant != FIN)
{
suivant = va_arg(vl,Point2D);
if (suivant != FIN) _pol.push_back(suivant);
}
va_end(vl);
}
// Fin code -------------------
FIN est un Point2D fixe servant de marqueur de fin.
Puis je teste en mettant 3 Point2D en dur et en
écrivant Poly2D Pol(A,B,C,FIN);
Sous VC++6.0 tout fonctionne, 0 errors et 0 warnings,
et l'exécution donne ce que je veux.
Sous CodeBlocks, 0 errors et 1 warning que je ne comprends
pas, et la ligne de test ci dessus fait sortir du programme,
mais sans la fenêtre d'erreur windows traditionnelle.
Le warning est:
"cannot receive objects of non-POD type"
puis:
"cannot pass objects of non-POD type" 3 fois.
Que signifie POD ?
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
Sous VC++6.0 tout fonctionne, 0 errors et 0 warnings, et l'exécution donne ce que je veux. Sous CodeBlocks, 0 errors et 1 warning que je ne comprends pas, et la ligne de test ci dessus fait sortir du programme, mais sans la fenêtre d'erreur windows traditionnelle.
le fil a débattu de ce point, il y a peu, me référrant au comportement de VC, je partageais cette surprise d'y voir qlq chose de non standard. le fait est qu'en effet seul des POD peuvent être gérés proprement par les fonctions / macros (implémentation dépendent) va_xxx.
Que signifie POD ?
plain old data. un type primitif, un pointeur, des struct statiques (sans opérateur &) ...
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
un moyen est de transmettre une liste variable de pointeurs.
une autre façon possible est, au niveau de l'appelant, d'initialiser et remplir un autre container et de transmettre ce seul container (à la place des items), la méthode transférera alors les éléments de la "liste de transport" à la liste de l'instance.
Sylvain.
Etienne Rousee wrote on 21/02/2007 13:31:
Sous VC++6.0 tout fonctionne, 0 errors et 0 warnings,
et l'exécution donne ce que je veux.
Sous CodeBlocks, 0 errors et 1 warning que je ne comprends
pas, et la ligne de test ci dessus fait sortir du programme,
mais sans la fenêtre d'erreur windows traditionnelle.
le fil a débattu de ce point, il y a peu, me référrant au comportement
de VC, je partageais cette surprise d'y voir qlq chose de non standard.
le fait est qu'en effet seul des POD peuvent être gérés proprement par
les fonctions / macros (implémentation dépendent) va_xxx.
Que signifie POD ?
plain old data.
un type primitif, un pointeur, des struct statiques (sans opérateur &) ...
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
un moyen est de transmettre une liste variable de pointeurs.
une autre façon possible est, au niveau de l'appelant, d'initialiser et
remplir un autre container et de transmettre ce seul container (à la
place des items), la méthode transférera alors les éléments de la "liste
de transport" à la liste de l'instance.
Sous VC++6.0 tout fonctionne, 0 errors et 0 warnings, et l'exécution donne ce que je veux. Sous CodeBlocks, 0 errors et 1 warning que je ne comprends pas, et la ligne de test ci dessus fait sortir du programme, mais sans la fenêtre d'erreur windows traditionnelle.
le fil a débattu de ce point, il y a peu, me référrant au comportement de VC, je partageais cette surprise d'y voir qlq chose de non standard. le fait est qu'en effet seul des POD peuvent être gérés proprement par les fonctions / macros (implémentation dépendent) va_xxx.
Que signifie POD ?
plain old data. un type primitif, un pointeur, des struct statiques (sans opérateur &) ...
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
un moyen est de transmettre une liste variable de pointeurs.
une autre façon possible est, au niveau de l'appelant, d'initialiser et remplir un autre container et de transmettre ce seul container (à la place des items), la méthode transférera alors les éléments de la "liste de transport" à la liste de l'instance.
Sylvain.
Mathias Gaunard
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
L'overloading.
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
L'overloading.
Q'est ce que c'est ?
--
Etienne
Etienne Rousee
"Sylvain" a écrit ...
Etienne Rousee wrote on 21/02/2007 13:31:
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
un moyen est de transmettre une liste variable de pointeurs.
Merci beaucoup pour ces renseignements. Je vais essayer avec des pointeurs.
une autre façon possible est, au niveau de l'appelant, d'initialiser et remplir un autre container et de transmettre ce seul container (à la place des items), la méthode transférera alors les éléments de la "liste de transport" à la liste de l'instance.
Je vais y réfléchir.
--
Etienne
"Sylvain" <noSpam@mail.net> a écrit ...
Etienne Rousee wrote on 21/02/2007 13:31:
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
un moyen est de transmettre une liste variable de pointeurs.
Merci beaucoup pour ces renseignements.
Je vais essayer avec des pointeurs.
une autre façon possible est, au niveau de l'appelant, d'initialiser et
remplir un autre container et de transmettre ce seul container (à la
place des items), la méthode transférera alors les éléments de la "liste
de transport" à la liste de l'instance.
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
un moyen est de transmettre une liste variable de pointeurs.
Merci beaucoup pour ces renseignements. Je vais essayer avec des pointeurs.
une autre façon possible est, au niveau de l'appelant, d'initialiser et remplir un autre container et de transmettre ce seul container (à la place des items), la méthode transférera alors les éléments de la "liste de transport" à la liste de l'instance.
Je vais y réfléchir.
--
Etienne
Mathias Gaunard
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ? L'overloading.
Tu peux aussi utiliser les variadic templates pour générer les fonctions dont tu as besoin au fur et à mesure que tu les utilises.
Sylvain
Etienne Rousee wrote on 21/02/2007 19:22:
"Mathias Gaunard" a écrit ...
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ? L'overloading.
Q'est ce que c'est ?
sur *fr*.comp... on appelle cela la surcharge (de méthodes).
définir autant de convention d'appels que nécessaire est, en effet, possible puisque l'info nécessaire est dispo durant la compil. ... mais quelle lourdeur.
Sylvain.
Etienne Rousee wrote on 21/02/2007 19:22:
"Mathias Gaunard" <loufoque@gmail.com> a écrit ...
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ?
L'overloading.
Q'est ce que c'est ?
sur *fr*.comp... on appelle cela la surcharge (de méthodes).
définir autant de convention d'appels que nécessaire est, en effet,
possible puisque l'info nécessaire est dispo durant la compil. ... mais
quelle lourdeur.
Y a-t-il une autre façon d'obtenir une liste variable d'arguments ? L'overloading.
Q'est ce que c'est ?
sur *fr*.comp... on appelle cela la surcharge (de méthodes).
définir autant de convention d'appels que nécessaire est, en effet, possible puisque l'info nécessaire est dispo durant la compil. ... mais quelle lourdeur.
Sylvain.
James Kanze
Etienne Rousee wrote:
Y a-t-il quelque chose de non standard dans ceci:
J'ai une classe Point2D contenant deux doubles x et y et un constructeur, puis une classe Poly2D contenant un deque<Point2D>. Le problème se pose avec le constructeur de Poly2D qui admet une liste variable d'arguments. Voici son code:
va_start(vl,premier); _pol.push_back(premier); while (suivant != FIN) { suivant = va_arg(vl,Point2D); if (suivant != FIN) _pol.push_back(suivant); } va_end(vl); }
// Fin code -------------------
FIN est un Point2D fixe servant de marqueur de fin.
Comme a dit Sylvain, c'est un comportement indéfini. (En fait, avec un compilateur moderne, on pourrait toujours le faire marcher, mais historiquement, assurer la destruction sans savoir combien d'éléments il y avait posait pas mal de problèmes.)
La solution de Sylvain, avec des pointeurs (et un pointeur nul comme marque de fin) marche, mais a deux inconveniants : il ne permet pas de passer des temporaires (des expressions du genre « Point2D( 1.2, 3.4 ) »), et il est trop facile d'oublier le pointeur nul de fin (pointeur qui, au moins formellement, doit avoir le type Point2D const* -- un 0 ou le symbole NULL tout court ne suffit pas). Alors, il y a deux solutions classiques :
celle qui est à la mode :
On fait du constructeur un template, et on lui passe des itérateurs :
template< typename FwdIter > Poly2D::Poly2D( FwdIter begin, FwdIter end ) : _pol( begin, end ) { }
L'avantage, évidemment, c'est que tu te passes de toute la logique de la boucle dans ton code. En plus, si les itérateurs sont à accès aléatoire, l'implémentation de vector en profitera pour calcule la taille au départ, et ne faire qu'une seule allocation.
Le désavantage, évidemment, c'est que ça ne fait pas réelement la même chose. Il faut, par exemple, que tu as des paramètres quelque part d'où tu peux tirer des itérateurs, ce qui est loin d'être évident.
celle qui marche réelement :
On crée une classe « collecteur », qu'on passe. Le constructeur devient à peu près :
Le collecteur, au font, ce n'est rien d'autre qu'une classe qui contient un std::vector, et qui fournit aussi un moyen d'enchaîner des push_back ; std::vector lui-même ferait l'affaire si push_back renvoiait une référence à la collection. (Mais le nom push_back est un peu long pour cette utilisation. On préfère « with », voire l'opérateur << ou l'opérateur().) Quelque chose du genre ::
template< typename T > class Collector { public: Collector& with( T const& elem ) // ou Collector& operator()( T const& elem ) { myData.push_back( elem ) ; return *this ; } std::vector< T >::const_iterator begin() const { return myData.begin() ; } std::vector< T >::const_iterator end() const { return myData.end() ; }
(Si on surcharge l'opérateur () à la place, ôte les « .with ». Je le trouve légèrement plus lisible avec les « .with », mais AMHA la différence n'est pas énorme.)
Si on aime l'obfuscation, on peut même ajouter des surcharges de l'opérateur virgule :
(On remarque le deuxième jeu de parenthèse. C'est pourquoi je le considère un peu l'obfuscation ; quelqu'un qui lit le code risque de ne pas les voir de premier abord, et de ne pas comprendre ce qui se passe. Mais au moins, si tu les oublies, le compilateur râle.)
Enfin, si tu as une borne supérieur au nombre d'éléments, il y a toujours le surcharge. Un peu pénible à entrée (surtout si la borne supérieur est élevée. (Je me vois mal taper une centaine de constructeurs, tous rigueureusement identique sauf en ce qui concerne le nombre de paramètres. Mais un petit script d'AWK...)
-- 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
Etienne Rousee wrote:
Y a-t-il quelque chose de non standard dans ceci:
J'ai une classe Point2D contenant deux doubles
x et y et un constructeur, puis une classe Poly2D
contenant un deque<Point2D>. Le problème se
pose avec le constructeur de Poly2D qui admet
une liste variable d'arguments.
Voici son code:
va_start(vl,premier);
_pol.push_back(premier);
while (suivant != FIN)
{
suivant = va_arg(vl,Point2D);
if (suivant != FIN) _pol.push_back(suivant);
}
va_end(vl);
}
// Fin code -------------------
FIN est un Point2D fixe servant de marqueur de fin.
Comme a dit Sylvain, c'est un comportement indéfini. (En fait,
avec un compilateur moderne, on pourrait toujours le faire
marcher, mais historiquement, assurer la destruction sans savoir
combien d'éléments il y avait posait pas mal de problèmes.)
La solution de Sylvain, avec des pointeurs (et un pointeur nul
comme marque de fin) marche, mais a deux inconveniants :
il ne permet pas de passer des temporaires (des expressions du
genre « Point2D( 1.2, 3.4 ) »), et il est trop facile
d'oublier le pointeur nul de fin (pointeur qui, au moins
formellement, doit avoir le type Point2D const* -- un 0 ou le
symbole NULL tout court ne suffit pas). Alors, il y a deux
solutions classiques :
celle qui est à la mode :
On fait du constructeur un template, et on lui passe des
itérateurs :
template< typename FwdIter >
Poly2D::Poly2D( FwdIter begin, FwdIter end )
: _pol( begin, end )
{
}
L'avantage, évidemment, c'est que tu te passes de toute la
logique de la boucle dans ton code. En plus, si les
itérateurs sont à accès aléatoire, l'implémentation de
vector en profitera pour calcule la taille au départ, et ne
faire qu'une seule allocation.
Le désavantage, évidemment, c'est que ça ne fait pas
réelement la même chose. Il faut, par exemple, que tu as des
paramètres quelque part d'où tu peux tirer des itérateurs,
ce qui est loin d'être évident.
celle qui marche réelement :
On crée une classe « collecteur », qu'on passe. Le
constructeur devient à peu près :
Le collecteur, au font, ce n'est rien d'autre qu'une classe
qui contient un std::vector, et qui fournit aussi un moyen
d'enchaîner des push_back ; std::vector lui-même ferait
l'affaire si push_back renvoiait une référence à la
collection. (Mais le nom push_back est un peu long pour
cette utilisation. On préfère « with », voire l'opérateur
<< ou l'opérateur().) Quelque chose du genre ::
template< typename T >
class Collector
{
public:
Collector& with( T const& elem )
// ou Collector& operator()( T const& elem )
{
myData.push_back( elem ) ;
return *this ;
}
std::vector< T >::const_iterator begin() const
{
return myData.begin() ;
}
std::vector< T >::const_iterator end() const
{
return myData.end() ;
}
(Si on surcharge l'opérateur () à la place, ôte les
« .with ». Je le trouve légèrement plus lisible avec les
« .with », mais AMHA la différence n'est pas énorme.)
Si on aime l'obfuscation, on peut même ajouter des
surcharges de l'opérateur virgule :
(On remarque le deuxième jeu de parenthèse. C'est pourquoi
je le considère un peu l'obfuscation ; quelqu'un qui lit le
code risque de ne pas les voir de premier abord, et de ne
pas comprendre ce qui se passe. Mais au moins, si tu les
oublies, le compilateur râle.)
Enfin, si tu as une borne supérieur au nombre d'éléments, il y a
toujours le surcharge. Un peu pénible à entrée (surtout si la
borne supérieur est élevée. (Je me vois mal taper une centaine
de constructeurs, tous rigueureusement identique sauf en ce qui
concerne le nombre de paramètres. Mais un petit script d'AWK...)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
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
J'ai une classe Point2D contenant deux doubles x et y et un constructeur, puis une classe Poly2D contenant un deque<Point2D>. Le problème se pose avec le constructeur de Poly2D qui admet une liste variable d'arguments. Voici son code:
va_start(vl,premier); _pol.push_back(premier); while (suivant != FIN) { suivant = va_arg(vl,Point2D); if (suivant != FIN) _pol.push_back(suivant); } va_end(vl); }
// Fin code -------------------
FIN est un Point2D fixe servant de marqueur de fin.
Comme a dit Sylvain, c'est un comportement indéfini. (En fait, avec un compilateur moderne, on pourrait toujours le faire marcher, mais historiquement, assurer la destruction sans savoir combien d'éléments il y avait posait pas mal de problèmes.)
La solution de Sylvain, avec des pointeurs (et un pointeur nul comme marque de fin) marche, mais a deux inconveniants : il ne permet pas de passer des temporaires (des expressions du genre « Point2D( 1.2, 3.4 ) »), et il est trop facile d'oublier le pointeur nul de fin (pointeur qui, au moins formellement, doit avoir le type Point2D const* -- un 0 ou le symbole NULL tout court ne suffit pas). Alors, il y a deux solutions classiques :
celle qui est à la mode :
On fait du constructeur un template, et on lui passe des itérateurs :
template< typename FwdIter > Poly2D::Poly2D( FwdIter begin, FwdIter end ) : _pol( begin, end ) { }
L'avantage, évidemment, c'est que tu te passes de toute la logique de la boucle dans ton code. En plus, si les itérateurs sont à accès aléatoire, l'implémentation de vector en profitera pour calcule la taille au départ, et ne faire qu'une seule allocation.
Le désavantage, évidemment, c'est que ça ne fait pas réelement la même chose. Il faut, par exemple, que tu as des paramètres quelque part d'où tu peux tirer des itérateurs, ce qui est loin d'être évident.
celle qui marche réelement :
On crée une classe « collecteur », qu'on passe. Le constructeur devient à peu près :
Le collecteur, au font, ce n'est rien d'autre qu'une classe qui contient un std::vector, et qui fournit aussi un moyen d'enchaîner des push_back ; std::vector lui-même ferait l'affaire si push_back renvoiait une référence à la collection. (Mais le nom push_back est un peu long pour cette utilisation. On préfère « with », voire l'opérateur << ou l'opérateur().) Quelque chose du genre ::
template< typename T > class Collector { public: Collector& with( T const& elem ) // ou Collector& operator()( T const& elem ) { myData.push_back( elem ) ; return *this ; } std::vector< T >::const_iterator begin() const { return myData.begin() ; } std::vector< T >::const_iterator end() const { return myData.end() ; }
(Si on surcharge l'opérateur () à la place, ôte les « .with ». Je le trouve légèrement plus lisible avec les « .with », mais AMHA la différence n'est pas énorme.)
Si on aime l'obfuscation, on peut même ajouter des surcharges de l'opérateur virgule :
(On remarque le deuxième jeu de parenthèse. C'est pourquoi je le considère un peu l'obfuscation ; quelqu'un qui lit le code risque de ne pas les voir de premier abord, et de ne pas comprendre ce qui se passe. Mais au moins, si tu les oublies, le compilateur râle.)
Enfin, si tu as une borne supérieur au nombre d'éléments, il y a toujours le surcharge. Un peu pénible à entrée (surtout si la borne supérieur est élevée. (Je me vois mal taper une centaine de constructeurs, tous rigueureusement identique sauf en ce qui concerne le nombre de paramètres. Mais un petit script d'AWK...)
-- 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
Etienne Rousee
"James Kanze" a écrit ...
Comme a dit Sylvain, c'est un comportement indéfini. (En fait, avec un compilateur moderne, on pourrait toujours le faire marcher, mais historiquement, assurer la destruction sans savoir combien d'éléments il y avait posait pas mal de problèmes.)
Il suffit que Poly2D ait un destructeur correct, non ?
La solution de Sylvain, avec des pointeurs (et un pointeur nul comme marque de fin) marche, mais a deux inconveniants : il ne permet pas de passer des temporaires (des expressions du genre « Point2D( 1.2, 3.4 ) »),
Ben, ça me gêne aussi.
et il est trop facile d'oublier le pointeur nul de fin
C'est de la responsabilité du programmeur.
(pointeur qui, au moins formellement, doit avoir le type Point2D const* -- un 0 ou le symbole NULL tout court ne suffit pas).
Un cast dans le constructeur ne suffit pas ? Par exemple: if (premier == (Point2D *) NULL) ...........
Alors, il y a deux solutions classiques :
celle qui est à la mode : ........... Il faut, par exemple, que tu as des paramètres quelque part d'où tu peux tirer des itérateurs, ce qui est loin d'être évident.
Je n'en ai pas justement.
celle qui marche réelement :
On crée une classe « collecteur », qu'on passe. Le constructeur devient à peu près :
Il y a une raison particulière pour que le collecteur soit template ?
Le collecteur, au font, ce n'est rien d'autre qu'une classe qui contient un std::vector, et qui fournit aussi un moyen d'enchaîner des push_back ; std::vector lui-même ferait l'affaire si push_back renvoiait une référence à la collection.
Est ce que Poly2D elle-même pourrait faire l'affaire ?
[snip code]
Ce code me paraît clair.
Si on aime l'obfuscation, on peut même ajouter des surcharges de l'opérateur virgule :
Ce qui est exactement ce que je veux pouvoir écrire. Tant pis pour les doubles parenthèses, il suffit de le savoir et de le commenter.
Enfin, si tu as une borne supérieur au nombre d'éléments, il y a toujours le surcharge. Un peu pénible à entrée (surtout si la borne supérieur est élevée.
Non, ça peut être quelconque.
Merci en tout cas pour toutes ces précisions.
--
Etienne
"James Kanze" <james.kanze@gmail.com> a écrit ...
Comme a dit Sylvain, c'est un comportement indéfini. (En fait,
avec un compilateur moderne, on pourrait toujours le faire
marcher, mais historiquement, assurer la destruction sans savoir
combien d'éléments il y avait posait pas mal de problèmes.)
Il suffit que Poly2D ait un destructeur correct, non ?
La solution de Sylvain, avec des pointeurs (et un pointeur nul
comme marque de fin) marche, mais a deux inconveniants :
il ne permet pas de passer des temporaires (des expressions du
genre « Point2D( 1.2, 3.4 ) »),
Ben, ça me gêne aussi.
et il est trop facile d'oublier le pointeur nul de fin
C'est de la responsabilité du programmeur.
(pointeur qui, au moins formellement, doit avoir
le type Point2D const* -- un 0 ou le symbole NULL
tout court ne suffit pas).
Un cast dans le constructeur ne suffit pas ?
Par exemple:
if (premier == (Point2D *) NULL) ...........
Alors, il y a deux solutions classiques :
celle qui est à la mode :
...........
Il faut, par exemple, que tu as des paramètres
quelque part d'où tu peux tirer des itérateurs,
ce qui est loin d'être évident.
Je n'en ai pas justement.
celle qui marche réelement :
On crée une classe « collecteur », qu'on passe. Le
constructeur devient à peu près :
Il y a une raison particulière pour que le collecteur soit template ?
Le collecteur, au font, ce n'est rien d'autre qu'une classe
qui contient un std::vector, et qui fournit aussi un moyen
d'enchaîner des push_back ; std::vector lui-même ferait
l'affaire si push_back renvoiait une référence à la
collection.
Est ce que Poly2D elle-même pourrait faire l'affaire ?
[snip code]
Ce code me paraît clair.
Si on aime l'obfuscation, on peut même ajouter des
surcharges de l'opérateur virgule :
Ce qui est exactement ce que je veux pouvoir écrire.
Tant pis pour les doubles parenthèses, il suffit de le savoir
et de le commenter.
Enfin, si tu as une borne supérieur au nombre d'éléments, il y a
toujours le surcharge. Un peu pénible à entrée (surtout si la
borne supérieur est élevée.
Comme a dit Sylvain, c'est un comportement indéfini. (En fait, avec un compilateur moderne, on pourrait toujours le faire marcher, mais historiquement, assurer la destruction sans savoir combien d'éléments il y avait posait pas mal de problèmes.)
Il suffit que Poly2D ait un destructeur correct, non ?
La solution de Sylvain, avec des pointeurs (et un pointeur nul comme marque de fin) marche, mais a deux inconveniants : il ne permet pas de passer des temporaires (des expressions du genre « Point2D( 1.2, 3.4 ) »),
Ben, ça me gêne aussi.
et il est trop facile d'oublier le pointeur nul de fin
C'est de la responsabilité du programmeur.
(pointeur qui, au moins formellement, doit avoir le type Point2D const* -- un 0 ou le symbole NULL tout court ne suffit pas).
Un cast dans le constructeur ne suffit pas ? Par exemple: if (premier == (Point2D *) NULL) ...........
Alors, il y a deux solutions classiques :
celle qui est à la mode : ........... Il faut, par exemple, que tu as des paramètres quelque part d'où tu peux tirer des itérateurs, ce qui est loin d'être évident.
Je n'en ai pas justement.
celle qui marche réelement :
On crée une classe « collecteur », qu'on passe. Le constructeur devient à peu près :
Il y a une raison particulière pour que le collecteur soit template ?
Le collecteur, au font, ce n'est rien d'autre qu'une classe qui contient un std::vector, et qui fournit aussi un moyen d'enchaîner des push_back ; std::vector lui-même ferait l'affaire si push_back renvoiait une référence à la collection.
Est ce que Poly2D elle-même pourrait faire l'affaire ?
[snip code]
Ce code me paraît clair.
Si on aime l'obfuscation, on peut même ajouter des surcharges de l'opérateur virgule :
Ce qui est exactement ce que je veux pouvoir écrire. Tant pis pour les doubles parenthèses, il suffit de le savoir et de le commenter.
Enfin, si tu as une borne supérieur au nombre d'éléments, il y a toujours le surcharge. Un peu pénible à entrée (surtout si la borne supérieur est élevée.
Non, ça peut être quelconque.
Merci en tout cas pour toutes ces précisions.
--
Etienne
Sylvain
Etienne Rousee wrote on 22/02/2007 17:46:
"James Kanze" a écrit ...
Comme a dit Sylvain, c'est un comportement indéfini. (En fait, avec un compilateur moderne, on pourrait toujours le faire marcher, mais historiquement, assurer la destruction sans savoir combien d'éléments il y avait posait pas mal de problèmes.)
Il suffit que Poly2D ait un destructeur correct, non ?
non, le pb est sur le destructeur des paramètres temporaires (Point2D) pas sur la classe proposant la méthode recevant ses params.
La solution de Sylvain, avec des pointeurs (et un pointeur nul comme marque de fin) marche, mais a deux inconveniants : il ne permet pas de passer des temporaires (des expressions du genre « Point2D( 1.2, 3.4 ) »),
Ben, ça me gêne aussi.
si rien d'autre n'est basé sur des pointeurs de point, ce serait nuisible (en plus de génant).
(pointeur qui, au moins formellement, doit avoir le type Point2D const* -- un 0 ou le symbole NULL tout court ne suffit pas).
Un cast dans le constructeur ne suffit pas ? Par exemple: if (premier == (Point2D *) NULL) ...........
le pb est de cast fait par va_arg.
Si on aime l'obfuscation, on peut même ajouter des surcharges de l'opérateur virgule :
J'aime bien :)
et comment ! ;) dommage même que tu utilises des instances non mutable, un:
je m'associe - mes règles ne sont pas aussi élégantes que celles de James et l'exemple proposé est très bien posé.
Sylvain.
Etienne Rousee wrote on 22/02/2007 17:46:
"James Kanze" <james.kanze@gmail.com> a écrit ...
Comme a dit Sylvain, c'est un comportement indéfini. (En fait,
avec un compilateur moderne, on pourrait toujours le faire
marcher, mais historiquement, assurer la destruction sans savoir
combien d'éléments il y avait posait pas mal de problèmes.)
Il suffit que Poly2D ait un destructeur correct, non ?
non, le pb est sur le destructeur des paramètres temporaires (Point2D)
pas sur la classe proposant la méthode recevant ses params.
La solution de Sylvain, avec des pointeurs (et un pointeur nul
comme marque de fin) marche, mais a deux inconveniants :
il ne permet pas de passer des temporaires (des expressions du
genre « Point2D( 1.2, 3.4 ) »),
Ben, ça me gêne aussi.
si rien d'autre n'est basé sur des pointeurs de point, ce serait
nuisible (en plus de génant).
(pointeur qui, au moins formellement, doit avoir
le type Point2D const* -- un 0 ou le symbole NULL
tout court ne suffit pas).
Un cast dans le constructeur ne suffit pas ?
Par exemple:
if (premier == (Point2D *) NULL) ...........
le pb est de cast fait par va_arg.
Si on aime l'obfuscation, on peut même ajouter des
surcharges de l'opérateur virgule :
J'aime bien :)
et comment ! ;)
dommage même que tu utilises des instances non mutable, un:
Comme a dit Sylvain, c'est un comportement indéfini. (En fait, avec un compilateur moderne, on pourrait toujours le faire marcher, mais historiquement, assurer la destruction sans savoir combien d'éléments il y avait posait pas mal de problèmes.)
Il suffit que Poly2D ait un destructeur correct, non ?
non, le pb est sur le destructeur des paramètres temporaires (Point2D) pas sur la classe proposant la méthode recevant ses params.
La solution de Sylvain, avec des pointeurs (et un pointeur nul comme marque de fin) marche, mais a deux inconveniants : il ne permet pas de passer des temporaires (des expressions du genre « Point2D( 1.2, 3.4 ) »),
Ben, ça me gêne aussi.
si rien d'autre n'est basé sur des pointeurs de point, ce serait nuisible (en plus de génant).
(pointeur qui, au moins formellement, doit avoir le type Point2D const* -- un 0 ou le symbole NULL tout court ne suffit pas).
Un cast dans le constructeur ne suffit pas ? Par exemple: if (premier == (Point2D *) NULL) ...........
le pb est de cast fait par va_arg.
Si on aime l'obfuscation, on peut même ajouter des surcharges de l'opérateur virgule :
J'aime bien :)
et comment ! ;) dommage même que tu utilises des instances non mutable, un: