Etienne Rousee wrote on 31/10/2006 18:25:[] est-il seulement un paramètre (qlq) utilisé pour les
opérateurs mathématiques de Entier ?
Aussi.
ok, donc N est un paramètre ""global et variable"" propre à un run.
une appli plus "grosse" (feuille de calcul à la mapple) devrait géré
différents ensemble (anneau ou pas) avec N distincts, mais je ne suis
pas sur que cela soit vital ici.
ie
Entier<N> operator+ (Entier<N> const& a, Entier<N> const& b){
return Entier<N>((a + b) % N);
}
Oui, j'ai écrit ça, mais en surcharge de méthode, pas de fonction
globale.
je ne l'ai pas présente in-situ mais je pensais à une méthode friend
bien sur (pas à une globale qui ne verrait que les instances "a" et "b",
ce ne sont pas 'a' ni 'b' qui sont sommées mais le nombre qu'ils
représentent).
"surcharge de méthode" est un peu vague, les opérateurs "à un paramètre"
(+=, *=, ...) sont des opérateurs membres,
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessairement) des
opérateurs non-membres
question subsidiaire, quelles est la limite de N ?
(32, 64 bits ou précision arbitraire ("BigInteger"))
En théorie, la plus grande possible, mais soyons réalistes,
pour le moment des int ou des long ordinaires me suffisent.
c'est bien la 1ière fois que je lis un matheux se contentant de "nombres
physiquement valides" ;)
De plus, je vais avoir une classe Anneau contenant une collection
d'Entier, et des opérateurs fonctionnant dessus.
je comprends le point ... et le problème venant du choix de mettre un
modulo dans Entier - la définition même de l'anneau présuppose
l'existence de N, mais pas celle des nombres entiers (surtout hors d'un
anneau), vouloir borner les nombres est une chose, figer le code (par
une écriture statique d'une classe template) en est une autre.
constructor) peut suffire.
Etienne Rousee wrote on 31/10/2006 18:25:
[] est-il seulement un paramètre (qlq) utilisé pour les
opérateurs mathématiques de Entier ?
Aussi.
ok, donc N est un paramètre ""global et variable"" propre à un run.
une appli plus "grosse" (feuille de calcul à la mapple) devrait géré
différents ensemble (anneau ou pas) avec N distincts, mais je ne suis
pas sur que cela soit vital ici.
ie
Entier<N> operator+ (Entier<N> const& a, Entier<N> const& b){
return Entier<N>((a + b) % N);
}
Oui, j'ai écrit ça, mais en surcharge de méthode, pas de fonction
globale.
je ne l'ai pas présente in-situ mais je pensais à une méthode friend
bien sur (pas à une globale qui ne verrait que les instances "a" et "b",
ce ne sont pas 'a' ni 'b' qui sont sommées mais le nombre qu'ils
représentent).
"surcharge de méthode" est un peu vague, les opérateurs "à un paramètre"
(+=, *=, ...) sont des opérateurs membres,
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessairement) des
opérateurs non-membres
question subsidiaire, quelles est la limite de N ?
(32, 64 bits ou précision arbitraire ("BigInteger"))
En théorie, la plus grande possible, mais soyons réalistes,
pour le moment des int ou des long ordinaires me suffisent.
c'est bien la 1ière fois que je lis un matheux se contentant de "nombres
physiquement valides" ;)
De plus, je vais avoir une classe Anneau contenant une collection
d'Entier, et des opérateurs fonctionnant dessus.
je comprends le point ... et le problème venant du choix de mettre un
modulo dans Entier - la définition même de l'anneau présuppose
l'existence de N, mais pas celle des nombres entiers (surtout hors d'un
anneau), vouloir borner les nombres est une chose, figer le code (par
une écriture statique d'une classe template) en est une autre.
constructor) peut suffire.
Etienne Rousee wrote on 31/10/2006 18:25:[] est-il seulement un paramètre (qlq) utilisé pour les
opérateurs mathématiques de Entier ?
Aussi.
ok, donc N est un paramètre ""global et variable"" propre à un run.
une appli plus "grosse" (feuille de calcul à la mapple) devrait géré
différents ensemble (anneau ou pas) avec N distincts, mais je ne suis
pas sur que cela soit vital ici.
ie
Entier<N> operator+ (Entier<N> const& a, Entier<N> const& b){
return Entier<N>((a + b) % N);
}
Oui, j'ai écrit ça, mais en surcharge de méthode, pas de fonction
globale.
je ne l'ai pas présente in-situ mais je pensais à une méthode friend
bien sur (pas à une globale qui ne verrait que les instances "a" et "b",
ce ne sont pas 'a' ni 'b' qui sont sommées mais le nombre qu'ils
représentent).
"surcharge de méthode" est un peu vague, les opérateurs "à un paramètre"
(+=, *=, ...) sont des opérateurs membres,
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessairement) des
opérateurs non-membres
question subsidiaire, quelles est la limite de N ?
(32, 64 bits ou précision arbitraire ("BigInteger"))
En théorie, la plus grande possible, mais soyons réalistes,
pour le moment des int ou des long ordinaires me suffisent.
c'est bien la 1ière fois que je lis un matheux se contentant de "nombres
physiquement valides" ;)
De plus, je vais avoir une classe Anneau contenant une collection
d'Entier, et des opérateurs fonctionnant dessus.
je comprends le point ... et le problème venant du choix de mettre un
modulo dans Entier - la définition même de l'anneau présuppose
l'existence de N, mais pas celle des nombres entiers (surtout hors d'un
anneau), vouloir borner les nombres est une chose, figer le code (par
une écriture statique d'une classe template) en est une autre.
constructor) peut suffire.
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessairement) des
opérateurs non-membres
Non, les deux choix sont possibles.
Le seul cas qui impose le choix global est le cas d'un opérateur binaire
avec un premier type sur lequel je n'ai pas de possibilité d'action,
soit parce qu'il est standard (int,long,float,double ....), soit parce qu'il
a été fabriqué par un voisin cachottier.
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessairement) des
opérateurs non-membres
Non, les deux choix sont possibles.
Le seul cas qui impose le choix global est le cas d'un opérateur binaire
avec un premier type sur lequel je n'ai pas de possibilité d'action,
soit parce qu'il est standard (int,long,float,double ....), soit parce qu'il
a été fabriqué par un voisin cachottier.
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessairement) des
opérateurs non-membres
Non, les deux choix sont possibles.
Le seul cas qui impose le choix global est le cas d'un opérateur binaire
avec un premier type sur lequel je n'ai pas de possibilité d'action,
soit parce qu'il est standard (int,long,float,double ....), soit parce qu'il
a été fabriqué par un voisin cachottier.
D'accord, mais ce n'est pas utilisable en pratique.
Mettons, par exemple, que je veuille construire
l'ensemple de tous les entiers modulo 10000:
cout << "N = ";
cin >> N; // je saisis 10000
vector <EntierDynamique <0,N> > Vect;
// puis 100 appels à Execute
D'accord, mais ce n'est pas utilisable en pratique.
Mettons, par exemple, que je veuille construire
l'ensemple de tous les entiers modulo 10000:
cout << "N = ";
cin >> N; // je saisis 10000
vector <EntierDynamique <0,N> > Vect;
// puis 100 appels à Execute
D'accord, mais ce n'est pas utilisable en pratique.
Mettons, par exemple, que je veuille construire
l'ensemple de tous les entiers modulo 10000:
cout << "N = ";
cin >> N; // je saisis 10000
vector <EntierDynamique <0,N> > Vect;
// puis 100 appels à Execute
donc entier::operator+(a, b) me plait mieux (mais les gouts z'et les
couleurs... à moins qu'il y ait une 'bonne' raison qui m'a echappée).
donc entier::operator+(a, b) me plait mieux (mais les gouts z'et les
couleurs... à moins qu'il y ait une 'bonne' raison qui m'a echappée).
donc entier::operator+(a, b) me plait mieux (mais les gouts z'et les
couleurs... à moins qu'il y ait une 'bonne' raison qui m'a echappée).
Par contre, je suis d'accord que ce n'est pas utilisable en pratique avec
une valeur de N aussi grande. Il peut y avoir des problèmes ou cette
technique a ces avantages. J'ai un petit morceau de code pour faire un
filtre gaussien sur une image. Avec les template sur la taille du filtre,
j'arrive a avoir un code relativement performant (le compilo optimize bien
les boucles avec des bornes fixées à des petits entiers). Si je veux
donner
le choix de la taille du filtre à l'utilisateur (disons entre 1 et 10 en x
et y), ca me fait 100 différents filtres, et ca peut valoir le coup de
conserver le template sur le filtre (donc un exe plus gros) pour avoir 100
codes générés et optimisés indépendamment par le compilateur.
Par contre, je suis d'accord que ce n'est pas utilisable en pratique avec
une valeur de N aussi grande. Il peut y avoir des problèmes ou cette
technique a ces avantages. J'ai un petit morceau de code pour faire un
filtre gaussien sur une image. Avec les template sur la taille du filtre,
j'arrive a avoir un code relativement performant (le compilo optimize bien
les boucles avec des bornes fixées à des petits entiers). Si je veux
donner
le choix de la taille du filtre à l'utilisateur (disons entre 1 et 10 en x
et y), ca me fait 100 différents filtres, et ca peut valoir le coup de
conserver le template sur le filtre (donc un exe plus gros) pour avoir 100
codes générés et optimisés indépendamment par le compilateur.
Par contre, je suis d'accord que ce n'est pas utilisable en pratique avec
une valeur de N aussi grande. Il peut y avoir des problèmes ou cette
technique a ces avantages. J'ai un petit morceau de code pour faire un
filtre gaussien sur une image. Avec les template sur la taille du filtre,
j'arrive a avoir un code relativement performant (le compilo optimize bien
les boucles avec des bornes fixées à des petits entiers). Si je veux
donner
le choix de la taille du filtre à l'utilisateur (disons entre 1 et 10 en x
et y), ca me fait 100 différents filtres, et ca peut valoir le coup de
conserver le template sur le filtre (donc un exe plus gros) pour avoir 100
codes générés et optimisés indépendamment par le compilateur.
Etienne Rousee wrote on 01/11/2006 00:13:les opérateurs "à deux paramètres" (+, *, ...) sont (nécessai rement) des
opérateurs non-membres
Non, les deux choix sont possibles.
Le seul cas qui impose le choix global est le cas d'un opérateur bina ire
avec un premier type sur lequel je n'ai pas de possibilité d'action,
soit parce qu'il est standard (int,long,float,double ....), soit parce qu'il
a été fabriqué par un voisin cachottier.
si tu veux, j'aurais du dire: cela a moins de sens et/ou peut être
confusant d'utiliser des opérateurs membres; des opérateurs 'globaux' me
paraissent plus compréhensible, en contre-partie ils seront (pour ne pas
se pénaliser) amis.
ainsi, en effet, le codage suivant est valide:
struct entier {
int val;
explicit entier(int x) { val = x; }
entier operator+ (entier const& x) const { return val + x.val; }
};
je préfère néanmoins:
struct entier {
...
friend entier operator+ (entier const& a, entier const& b){
return a.val + b.val;
}
};
simplement parce 'a' et 'b' sont totalement interchangeables et qu'il
n'y a pas de raison particulière dans
entier a(3);
entier b(2);
entier c = a + b;
à faire
a.operator+(b)
ou
b.operator+(a);
donc entier::operator+(a, b) me plait mieux (mais les gouts z'et les
couleurs... à moins qu'il y ait une 'bonne' raison qui m'a echappée).
Sylvain.
Etienne Rousee wrote on 01/11/2006 00:13:
les opérateurs "à deux paramètres" (+, *, ...) sont (nécessai rement) des
opérateurs non-membres
Non, les deux choix sont possibles.
Le seul cas qui impose le choix global est le cas d'un opérateur bina ire
avec un premier type sur lequel je n'ai pas de possibilité d'action,
soit parce qu'il est standard (int,long,float,double ....), soit parce qu'il
a été fabriqué par un voisin cachottier.
si tu veux, j'aurais du dire: cela a moins de sens et/ou peut être
confusant d'utiliser des opérateurs membres; des opérateurs 'globaux' me
paraissent plus compréhensible, en contre-partie ils seront (pour ne pas
se pénaliser) amis.
ainsi, en effet, le codage suivant est valide:
struct entier {
int val;
explicit entier(int x) { val = x; }
entier operator+ (entier const& x) const { return val + x.val; }
};
je préfère néanmoins:
struct entier {
...
friend entier operator+ (entier const& a, entier const& b){
return a.val + b.val;
}
};
simplement parce 'a' et 'b' sont totalement interchangeables et qu'il
n'y a pas de raison particulière dans
entier a(3);
entier b(2);
entier c = a + b;
à faire
a.operator+(b)
ou
b.operator+(a);
donc entier::operator+(a, b) me plait mieux (mais les gouts z'et les
couleurs... à moins qu'il y ait une 'bonne' raison qui m'a echappée).
Sylvain.
Etienne Rousee wrote on 01/11/2006 00:13:les opérateurs "à deux paramètres" (+, *, ...) sont (nécessai rement) des
opérateurs non-membres
Non, les deux choix sont possibles.
Le seul cas qui impose le choix global est le cas d'un opérateur bina ire
avec un premier type sur lequel je n'ai pas de possibilité d'action,
soit parce qu'il est standard (int,long,float,double ....), soit parce qu'il
a été fabriqué par un voisin cachottier.
si tu veux, j'aurais du dire: cela a moins de sens et/ou peut être
confusant d'utiliser des opérateurs membres; des opérateurs 'globaux' me
paraissent plus compréhensible, en contre-partie ils seront (pour ne pas
se pénaliser) amis.
ainsi, en effet, le codage suivant est valide:
struct entier {
int val;
explicit entier(int x) { val = x; }
entier operator+ (entier const& x) const { return val + x.val; }
};
je préfère néanmoins:
struct entier {
...
friend entier operator+ (entier const& a, entier const& b){
return a.val + b.val;
}
};
simplement parce 'a' et 'b' sont totalement interchangeables et qu'il
n'y a pas de raison particulière dans
entier a(3);
entier b(2);
entier c = a + b;
à faire
a.operator+(b)
ou
b.operator+(a);
donc entier::operator+(a, b) me plait mieux (mais les gouts z'et les
couleurs... à moins qu'il y ait une 'bonne' raison qui m'a echappée).
Sylvain.
"Vincent Lascaux" a écrit ...
cout << "N = ";
cin >> N; // je saisis 10000
vector <EntierDynamique <0,N> > Vect;
// puis 100 appels à Execute
"Vincent Lascaux" <nospam@nospam.invalid> a écrit ...
cout << "N = ";
cin >> N; // je saisis 10000
vector <EntierDynamique <0,N> > Vect;
// puis 100 appels à Execute
"Vincent Lascaux" a écrit ...
cout << "N = ";
cin >> N; // je saisis 10000
vector <EntierDynamique <0,N> > Vect;
// puis 100 appels à Execute
Oui, l'opérateur+ est en général un opérateur non-membre ami. Out re
ce que tu as dis, il y a une autre raison à utiliser ce design. Dans
la version non-membre, les 2 opérandes peuvent être le résultat
d'une conversion automatique. Dans la version membre, l'opérande de
gauche (paramète implicite this) ne peut pas être le résultat d'une
telle conversion.
Oui, l'opérateur+ est en général un opérateur non-membre ami. Out re
ce que tu as dis, il y a une autre raison à utiliser ce design. Dans
la version non-membre, les 2 opérandes peuvent être le résultat
d'une conversion automatique. Dans la version membre, l'opérande de
gauche (paramète implicite this) ne peut pas être le résultat d'une
telle conversion.
Oui, l'opérateur+ est en général un opérateur non-membre ami. Out re
ce que tu as dis, il y a une autre raison à utiliser ce design. Dans
la version non-membre, les 2 opérandes peuvent être le résultat
d'une conversion automatique. Dans la version membre, l'opérande de
gauche (paramète implicite this) ne peut pas être le résultat d'une
telle conversion.
wrote:Oui, l'opérateur+ est en général un opérateur non-membre ami. O utre
ce que tu as dis, il y a une autre raison à utiliser ce design. Dans
la version non-membre, les 2 opérandes peuvent être le résultat
d'une conversion automatique. Dans la version membre, l'opérande de
gauche (paramète implicite this) ne peut pas être le résultat d'u ne
telle conversion.
Oui et non. Très, très souvent, l'implémentation de l'operator+
est simplement :
MonType
operator+( MonType const& lhs, MonType const& rhs )
{
MonType tmp( lhs ) ;
lhs += rhs ;
return lhs ;
}
Et évidemment, le constructeur de copie et l'opérateur += sont
des fonctions publiques. Du coup, aucune raison de faire
operator+ un ami.
Sauf, évidemment, si on veut généraliser cette technique, au
moyen du Barton-Nackman trick. Mais alors, les opérateurs ne sont
pas amis afin d'accéder aux éléments privés, mais seulement
parce que c'est la seule façon de fournir l'implémentation d'une
fonction libre dans la définition de la classe. (Voir le
composant Operators, sous-système Basic dans ma bibliothèque
utilitaire, par exemple.)
MonType tmp( lhs ) ;
lhs += rhs ;
return lhs ;
dieu.tout.puissant@gmail.com wrote:
Oui, l'opérateur+ est en général un opérateur non-membre ami. O utre
ce que tu as dis, il y a une autre raison à utiliser ce design. Dans
la version non-membre, les 2 opérandes peuvent être le résultat
d'une conversion automatique. Dans la version membre, l'opérande de
gauche (paramète implicite this) ne peut pas être le résultat d'u ne
telle conversion.
Oui et non. Très, très souvent, l'implémentation de l'operator+
est simplement :
MonType
operator+( MonType const& lhs, MonType const& rhs )
{
MonType tmp( lhs ) ;
lhs += rhs ;
return lhs ;
}
Et évidemment, le constructeur de copie et l'opérateur += sont
des fonctions publiques. Du coup, aucune raison de faire
operator+ un ami.
Sauf, évidemment, si on veut généraliser cette technique, au
moyen du Barton-Nackman trick. Mais alors, les opérateurs ne sont
pas amis afin d'accéder aux éléments privés, mais seulement
parce que c'est la seule façon de fournir l'implémentation d'une
fonction libre dans la définition de la classe. (Voir le
composant Operators, sous-système Basic dans ma bibliothèque
utilitaire, par exemple.)
MonType tmp( lhs ) ;
lhs += rhs ;
return lhs ;
wrote:Oui, l'opérateur+ est en général un opérateur non-membre ami. O utre
ce que tu as dis, il y a une autre raison à utiliser ce design. Dans
la version non-membre, les 2 opérandes peuvent être le résultat
d'une conversion automatique. Dans la version membre, l'opérande de
gauche (paramète implicite this) ne peut pas être le résultat d'u ne
telle conversion.
Oui et non. Très, très souvent, l'implémentation de l'operator+
est simplement :
MonType
operator+( MonType const& lhs, MonType const& rhs )
{
MonType tmp( lhs ) ;
lhs += rhs ;
return lhs ;
}
Et évidemment, le constructeur de copie et l'opérateur += sont
des fonctions publiques. Du coup, aucune raison de faire
operator+ un ami.
Sauf, évidemment, si on veut généraliser cette technique, au
moyen du Barton-Nackman trick. Mais alors, les opérateurs ne sont
pas amis afin d'accéder aux éléments privés, mais seulement
parce que c'est la seule façon de fournir l'implémentation d'une
fonction libre dans la définition de la classe. (Voir le
composant Operators, sous-système Basic dans ma bibliothèque
utilitaire, par exemple.)
MonType tmp( lhs ) ;
lhs += rhs ;
return lhs ;
Exact, en supposant que tu voulais écrire :
MonType tmp( lhs ) ;
tmp += rhs ;
return tmp ;
On pourrait aussi écrire :
MonType
operator+( MonType const& lhs, MonType const& rhs )
{
return MonType ( lhs ) += rhs;
}
Enfin, on pourrait également écrire :
MonType
operator+( MonType lhs, MonType const& rhs )
{
return lhs += rhs;
}
Exact, en supposant que tu voulais écrire :
MonType tmp( lhs ) ;
tmp += rhs ;
return tmp ;
On pourrait aussi écrire :
MonType
operator+( MonType const& lhs, MonType const& rhs )
{
return MonType ( lhs ) += rhs;
}
Enfin, on pourrait également écrire :
MonType
operator+( MonType lhs, MonType const& rhs )
{
return lhs += rhs;
}
Exact, en supposant que tu voulais écrire :
MonType tmp( lhs ) ;
tmp += rhs ;
return tmp ;
On pourrait aussi écrire :
MonType
operator+( MonType const& lhs, MonType const& rhs )
{
return MonType ( lhs ) += rhs;
}
Enfin, on pourrait également écrire :
MonType
operator+( MonType lhs, MonType const& rhs )
{
return lhs += rhs;
}