OVH Cloud OVH Cloud

Template et constante

64 réponses
Avatar
Etienne Rousee
Bonjour,

Le code suivant ne compile pas parce que
k n'est pas une constante:

template <int N> class Entier
{
........
};

int k = 5;

Entier <k> l;

Y aurait il une autre construction permettant de faire ça ?
Mon contexte est l'implémentation des anneaux Z/nZ,
des polynômes à coeefficients là dedans, et de quelques
calculs de groupes.

--

Etienne

10 réponses

1 2 3 4 5
Avatar
Jean-Marc Bourguet
"Etienne Rousee" writes:

"Jean-Marc Bourguet" a écrit ...
les templates.


Qu'est-ce que tu voulais que les templates t'apportent?


Ça me paraissait la méthode adaptée à ce que je voulais,
la plus simple. Ce n'est peut-être pas le cas.

A noter que:

template <int& N>
class foo { ... };

int x;

foo<x> bar;

est possible.


Pas pour VC++ 6.0 (Je sais, c'est une pièce de musée).


Je ne sais pas. Je ne l'ai jamais utilisé.

À noter qu'il faut que x soit une variable globale non statique.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
Sylvain
Etienne Rousee wrote on 30/10/2006 18:15:

Sur mon système (W2000pro + VC6.0 + 512Mo),
on atteint les limites internes avec 280, alors 10000 !!...


c'est ici la limite avec une heap de compilation par défaut (en principe
aux alentours de 105Mo).

le paramètre /Zm du compilo sert à définir en % l'allocation max.,
/Zm200 donne 200% de 100Mo soit 210Mo

le paramètre maximal documentée est 2000, avec 1400 (1,4Go) on peut
monter à N000 (+1 mn de compil).

Sylvain.

Avatar
Sylvain
Etienne Rousee wrote on 30/10/2006 17:59:

quelles sont les occurences de 'N' dans le patron défini ? leur nombre,
leur implication par rapport à l'algorithmie de la classe, ... ?


C'est le n de Z/nZ.


ok, je l'avais compris comme cela.
mais cela ne concerne que Entier, pas un anneau dont lequel il existe
peut-être, donc en reformulant, est-ce que N est vraiment le paramètre n
de "Z/nZ" et donc sera sûrement discret car premier (pour que l'anneau
soit un groupe) ou est-il seulement un paramètre (qlq) utilisé pour les
opérateurs mathématiques de Entier ?

ie
Entier<N> operator+ (Entier<N> const& a, Entier<N> const& b){
return Entier<N>((a + b) % N);
}

question subsidiaire, quelles est la limite de N ?
(32, 64 bits ou précision arbitraire ("BigInteger"))

plus avant que représente la classe Entier par rapport à un anneau?


Un "Entier" est un entier modulo N.


reste un doute (ou je ne suis pas sur de bien comprendre)
Entier stocke-t-il la partie congrue à N d'un nombre (0 <= contenu de
Entier < N) ou stocke-t-il une valeur quelconque, le modulo
n'intervenant que dans les opérateurs numériques ?

Sylvain.


Avatar
dieu.tout.puissant
Etienne Rousee wrote:
"Jean-Marc Bourguet" a écrit ...
les templates.


Qu'est-ce que tu voulais que les templates t'apportent?


Ça me paraissait la méthode adaptée à ce que je voulais,
la plus simple. Ce n'est peut-être pas le cas.

A noter que:

template <int& N>
class foo { ... };

int x;

foo<x> bar;

est possible.


Pas pour VC++ 6.0 (Je sais, c'est une pièce de musée).
Je vais essayer avec autre chose.


1. VC++ 6.0 a un support très limité des templates :/

2.
int x;



L'adresse de "x" doit être connu par le linker pour que le template
puisse être instancié.
=> x doit être une variable globale non statique.

3.
template <int& N> : N désigne une variable (lvalue)
template <int N> : N désigne une constante (rvalue)

Ces 2 expressions n'ont donc pas le même champs d'application.

Par exemple, tu ne peux pas définir foo de cette manière :
template <int& N>
class foo {
int tab[N];
};

alors que c'est possible avec "template <int N>"

Au fait, que pensez vous (collectif) du nouveau turbo C++ ?


Tu me l'apprends!
Je vais le tester sous peu.



Avatar
James Kanze
Jean-Marc Bourguet wrote:
"Etienne Rousee" writes:


[...]
Oui, mais ça reste inapplicable dans mon cas.
Je crois que je n'ai pas le choix, il faut que j'abandonne
les templates.


Qu'est-ce que tu voulais que les templates t'apportent?


Des validations de type. Avec des templates, Entier< 5 > et
Entier< 6 > sont deux types distinctes. Et si je n'ai pas prévu
des conversions implicites ou des opérateurs mixtes, quelque
chose du genre :

Entier< 5 > x ;
Entier< 6 > y ;
x = y ;

serait une erreur lors de la compilation. (Si j'utilise un
paramètre au constructeur, en revanche, le mieux que je peux
faire, c'est une erreur à l'exécution.)

Si je veux supporter ce genre de chose, les templates sont une
mauvaise solution, mais sinon, c'est la solution à préférer.

A noter que:

template <int& N>
class foo { ... };

int x;

foo<x> bar;

est possible.


Est-ce que « template< int const& N > » ne serait pas mieux ?
Voire même avec « int const » comme paramètre. (Mais
attention : il faut que l'int ait un linkage global, donc,
qu'il soit défini dans une portée référentielle et qu'il ait une
durée de vie statique. Si on veut l'initialiser à partir des
paramètres de la ligne de commande, il faut tricher un peu avec
le chargement dynamique pour différer l'initialisation
jusqu'après l'entrée dans main.

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


Avatar
Vincent Lascaux
"Etienne Rousee" a écrit dans le message de news:
45463372$0$5101$

"Vincent Lascaux" a écrit ...
Juste pour le fun:

template<int N>
struct EntierDynamique
{
static inline bool Execute(int n)
{
if (!EntierDynamique<N - 1>::Execute(N - 1) && n == N)
{
Entier<N> l; ...
return true;
}
else
return false;
}
};
template<>
struct EntierDynamique<0>
{
static inline bool Execute(int n)
{
return false;
}
};

EntierDynamique<100000>::Execute(k);


C'est amusant.
Sur mon système (W2000pro + VC6.0 + 512Mo),
on atteint les limites internes avec 280, alors 10000 !!...


Effectivement... comme je l'ai dit, c'était non testé... Le code suivant non
testé non plus devrait permettre d'aller beaucoup plus loin (au limite des
entiers ?)

template<int Low, int High>
struct EntierDynamique
{
static void Execute(int n)
{
const int Mid = (Low + High) / 2
if (n < Mid)
{
EntierDynamique<Low, Mid - 1>::Execute(n);
} else if (n > Mid) {
EntierDynamique<Mid + 1, Low>::Execute(n);
} else {
Entier<N> l; ...
}
}
};
template<int N>
struct EntierDynamique<N, N>
{
static void Execute() { }
};
template<int N>
struct EntierDynamique<N, N - 1>
{
static void Execute() { }
};
EntierDynamique<0, 10000>::Execute(k);

devrait etre remplacé par
if (k < 5000)
{
if (k < 2499)
{
if (k < 1248)
{
if (k < 623)
{
if (k < 310)
{
if (k < 154)
{
if (k < 76)
{
if (k < 37)
{
if (k < 17)
{
if (k < 7)
{
if (k < 2)
{
if (k < 0) { }
else if (k > 0) { }
else { Entier<0> l; ...
} else if (k > 2) {
if (n < 4)
{
if (k < 3) { }
else if (k > 3) { }
else { Entier<3> l; ... }
} else if (n > 4) {
.......
}

Et je vous laisse finir.
Ca devrait jamais aller très profond, et donc permettre des long temps de
compilation :)

--
Vincent


Avatar
Etienne Rousee
"Sylvain" a écrit ...
Etienne Rousee wrote on 30/10/2006 17:59:

quelles sont les occurences de 'N' dans le patron défini ? leur nombre,
leur implication par rapport à l'algorithmie de la classe, ... ?


C'est le n de Z/nZ.


ok, je l'avais compris comme cela.
mais cela ne concerne que Entier, pas un anneau dont lequel il existe
peut-être, donc en reformulant, est-ce que N est vraiment le paramètre n
de "Z/nZ" et donc sera sûrement discret car premier (pour que l'anneau
soit un groupe)


Non, les cas où N n'est pas premier m'intéressent aussi.

ou est-il seulement un paramètre (qlq) utilisé pour les
opérateurs mathématiques de Entier ?


Aussi.

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.

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.

plus avant que représente la classe Entier par rapport à un anneau?


Un "Entier" est un entier modulo N.



De plus, je vais avoir une classe Anneau contenant une collection
d'Entier, et des opérateur fonctionnant dessus.
Par exemple,je voudrais modéliser les notions d'idéal, de quotient
par un idéal, de produit direct ou semi-direct, d'isomorphisme,
enfin, tout ce que je pourrai modéliser en matière d'opérations
algébriques.

reste un doute (ou je ne suis pas sur de bien comprendre)
Entier stocke-t-il la partie congrue à N d'un nombre (0 <= contenu de
Entier < N)


Oui.

ou stocke-t-il une valeur quelconque, le modulo
n'intervenant que dans les opérateurs numériques ?


Non.

--

Etienne



Avatar
Etienne Rousee
"Vincent Lascaux" a écrit ...
Effectivement... comme je l'ai dit, c'était non testé... Le code suivant
non

testé non plus devrait permettre d'aller beaucoup plus loin (au limite des
entiers ?)

template<int Low, int High>
struct EntierDynamique
{
static void Execute(int n)
{
const int Mid = (Low + High) / 2
if (n < Mid)
{
EntierDynamique<Low, Mid - 1>::Execute(n);
} else if (n > Mid) {
EntierDynamique<Mid + 1, Low>::Execute(n);
} else {
Entier<N> l; ...
}
}
};
template<int N>
struct EntierDynamique<N, N>
{
static void Execute() { }
};
template<int N>
struct EntierDynamique<N, N - 1>
{
static void Execute() { }
};
EntierDynamique<0, 10000>::Execute(k);


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

--

Etienne

Avatar
Etienne Rousee
"James Kanze" a écrit ...
Jean-Marc Bourguet wrote:
Qu'est-ce que tu voulais que les templates t'apportent?


Des validations de type. Avec des templates, Entier< 5 > et
Entier< 6 > sont deux types distinctes. Et si je n'ai pas prévu
des conversions implicites ou des opérateurs mixtes, quelque
chose du genre :

Entier< 5 > x ;
Entier< 6 > y ;
x = y ;

serait une erreur lors de la compilation. (Si j'utilise un
paramètre au constructeur, en revanche, le mieux que je peux
faire, c'est une erreur à l'exécution.)


Oui, effectivement.

Si je veux supporter ce genre de chose, les templates sont une
mauvaise solution, mais sinon, c'est la solution à préférer.


Uniquement dans le cas des applications canoniques entre
Z/mZ et Z/nZ si n est divisible par m (injection et projection)

--

Etienne


Avatar
Sylvain
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.

soit tu utilises un template <N> et compiles, run, puis edite,
recompile, rerun, etc, etc.
soit tu le gères comme un static global.

(je fais ici l'hypothèse d'un "petit" code de calcul souvent itéré - via
une saisie console, un input file, ...).

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
éventuellement amis.

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" ;)

plus avant que représente la classe Entier par rapport à un anneau?
Un "Entier" est un entier modulo N.




De plus, je vais avoir une classe Anneau contenant une collection
d'Entier, et des opérateur 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.

reste un doute (ou je ne suis pas sur de bien comprendre)
Entier stocke-t-il la partie congrue à N d'un nombre (0 <= contenu de
Entier < N)
Oui.



peut-être qu'une factory d'Entier (ou un ajustement dans son
constructor) peut suffire.

Sylvain.




1 2 3 4 5