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
Manuel Zaccaria
Etienne Rousee a écrit:
Bonjour,


Bonjour,


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

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

int k = 5;


int const k = 5;

ou bien:

enum { k = 5 };

Du coup, k est une constante de compilation
et n'est plus modifiable par la suite.


Entier <k> l;



-
Manuel Zaccaria

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


Si k est une constante il faut la déclarer const pour que
cela fonctionne.

Sinon il faut trouver un moyen pour convertir le polymorphisme
statique (les templates) en polymorphisme dynamique (variant
pendant l'exécution). Par exemple :

switch(k)
{
case 1: {Entier<1> l; ...} break;
case 2: {Entier<2> l; ...} break;
case 3: {Entier<3> l; ...} break;
case 4: {Entier<4> l; ...} break;
case 5: {Entier<5> l; ...} break;
}

Mais si on en arrive là, il y a de fortes changes qu'il y ait
un problème de conception quelque part. Les templates ne sont
peut être pas la bonne solution.

--
Sylvain Togni

Avatar
Etienne Rousee
"Sylvain Togni" a écrit...
Si k est une constante il faut la déclarer const pour que
cela fonctionne.


Ce n'est pas le cas, k peut être saisi par l'utilisateur.

Sinon il faut trouver un moyen pour convertir le polymorphisme
statique (les templates) en polymorphisme dynamique (variant
pendant l'exécution). Par exemple :

switch(k)
{
case 1: {Entier<1> l; ...} break;
case 2: {Entier<2> l; ...} break;
case 3: {Entier<3> l; ...} break;
case 4: {Entier<4> l; ...} break;
case 5: {Entier<5> l; ...} break;
}


Ceci fait bien ce que je voudrais, mais il faudrais alors
que je mette des milliers de lignes dans mon switch.
Et ceci que pour l ....... Et il n'est pas seul ....

Mais si on en arrive là, il y a de fortes changes qu'il y ait
un problème de conception quelque part. Les templates ne sont
peut être pas la bonne solution.


Peut-être bien, je vais réfléchir à la question.

--

Etienne

Avatar
Sylvain
Etienne Rousee wrote on 29/10/2006 17:48:

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

int k = 5;
Entier <k> l;

Y aurait il une autre construction permettant de faire ça ?


"ça" est assez peu décrit par ce qui précéde!
quelles sont les occurences de 'N' dans le patron défini ? leur nombre,
leur implication par rapport à l'algorithmie de la classe, ... ?

plus avant que représente la classe Entier par rapport à un anneau?
s'il s'agit seulement d'un entier à qui pourra être appliqué mod N pour
déterminer si ce résultat est congru à la "caractéristique" N du
template, cela me parait un petit peu compliqué.

Mon contexte est l'implémentation des anneaux Z/nZ,
des polynômes à coeefficients là dedans, et de quelques
calculs de groupes.


si le paramètre template 'N' est le modulus de l'anneau, on pourra
surement définir:

class Entier {
private:
int n;
...
public:
Entier(int mod) : n(mod) { ... }
...
};

tous les calculs internes faisant intervenir n comme une donnée membre
seront codés à l'identique par substitution de N constante en ce n.

Sylvain.

Avatar
Vincent Lascaux
switch(k)
{
case 1: {Entier<1> l; ...} break;
case 2: {Entier<2> l; ...} break;
case 3: {Entier<3> l; ...} break;
case 4: {Entier<4> l; ...} break;
case 5: {Entier<5> l; ...} break;
}


Ceci fait bien ce que je voudrais, mais il faudrais alors
que je mette des milliers de lignes dans mon switch.
Et ceci que pour l ....... Et il n'est pas seul ....


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

devrait être remplacé à la compilation par quelque chose qui ressemblerait à
ce code (mais ne l'est probablement pas vu que j'ai pas testé :P)

if (k == 1)
{
Entier<1> l; ...
} else if (k == 2) {
Entier<2> l; ...
} else if (k == 3) {
Entier<3> l; ...
} else ..... {
} else if (k == 100000) {
Entier<100000> l; ...
}

et vaut true si k était dans 1 .. 100 000
Mais bon, bonjour le temps de compilation, la taille de l'exe :)
En s'amusant on doit pouvoir obtenir une recherche un peu plus en arbre de
la bonne valeur... Je sais pas trop comment simuler un vrai switch avec les
templates par contre.

--
Vincent


Avatar
Loïc Joly
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);

devrait être remplacé à la compilation par quelque chose qui ressemblerait à
ce code (mais ne l'est probablement pas vu que j'ai pas testé :P)


Il y a de fortes chances que ce genre de chose dépasse la profondeur
d'instanciation de template du compilateur. J'ai déjà vu du code qui ne
se basais pas sur du <N-1> mais sur du <N/2> (avec gestion des restes,
bien entendu) pour contourner ce genre de problème.

--
Loïc

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

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

int k = 5;
Entier <k> l;

Y aurait il une autre construction permettant de faire ça ?


"ça" est assez peu décrit par ce qui précéde!
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.

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


Un "Entier" est un entier modulo N.

s'il s'agit seulement d'un entier à qui pourra être appliqué mod N pour
déterminer si ce résultat est congru à la "caractéristique" N du
template, cela me parait un petit peu compliqué.


J'ai déjà surchargé tous les opérateurs algébriques pour cette
classe et tout marche quand on fait des déclarations avec N
en dur (constant) dans le programme.

Mon contexte est l'implémentation des anneaux Z/nZ,
des polynômes à coeefficients là dedans, et de quelques
calculs de groupes.


si le paramètre template 'N' est le modulus de l'anneau, on pourra
surement définir:

class Entier {
private:
int n;
...
public:
Entier(int mod) : n(mod) { ... }
...
};


Ben oui, c'est ce qui m'ennuie, mais bon, tant pis.

--

Etienne


Avatar
Etienne Rousee
"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 !!...

--

Etienne

Avatar
Etienne Rousee
"Loïc Joly" a écrit ...
Il y a de fortes chances que ce genre de chose dépasse la profondeur
d'instanciation de template du compilateur.


Oui, c'est le cas à partir de N = 281.

J'ai déjà vu du code qui ne se basais pas sur du <N-1>
mais sur du <N/2> (avec gestion des restes,
bien entendu) pour contourner ce genre de problème.


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

--

Etienne

Avatar
Jean-Marc Bourguet
"Etienne Rousee" writes:

"Loïc Joly" a écrit ...
Il y a de fortes chances que ce genre de chose dépasse la profondeur
d'instanciation de template du compilateur.


Oui, c'est le cas à partir de N = 281.

J'ai déjà vu du code qui ne se basais pas sur du <N-1>
mais sur du <N/2> (avec gestion des restes,
bien entendu) pour contourner ce genre de problème.


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?

A noter que:

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

int x;

foo<x> bar;

est possible.

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


1 2 3 4 5