Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Utilisation d'un typedef d'un énuméré dans une classe template

12 réponses
Avatar
Pascal Béthune
Bonjour,


Soit le code suivant:


class MyValueTrait
{
public:
enum ValueEnum { A, B, C, D, END };
};

template < class ValueTrait >
class Collection
{
public:
typedef typename ValueTrait::ValueEnum ValueEnum;

int & operator[]( ValueEnum valueEnum )
{
// source simplifié pour le post
return value_;
}

int value_;
};

L'instantiation du template ne pose pas de problème:


int main()
{
Collection< MyValueTrait > collection;


L'utilisation de la méthode en utilisant l'énuméré de la classe
MyValueTrait ne pose pas de problème non plus:


collection[ MyValueTrait::A ] = 3;


Mais, si j'utilise l'énuméré de la classe template, ça ne fonctionne pas:


collection[ Collection< MyValueTrait >::A ] = 3; // ligne 37

return 0;
}


J'ai le message suivant (gcc 3.3.3 sur fedora core 2):


g++ -Wall -ansi -o extrait extrait.cpp
extrait.cpp: Dans function « int main() »:
extrait.cpp:37: error: `A' is not a member of type
`Collection<MyValueTrait>'


Pourquoi le typedef de la classe Collection ne me permet t-il pas
d'écrire cela ? Y a t-il un autre moyen de faire ? Est-ce un
bug/limitation de gcc ?


-- Pascal

10 réponses

1 2
Avatar
Fabien LE LEZ
On Fri, 19 Nov 2004 22:54:41 +0100, Pascal Béthune :

extrait.cpp:37: error: `A' is not a member of type
`Collection<MyValueTrait>'


Est-ce une erreur, d'après toi ?

La ligne "typedef typename ValueTrait::ValueEnum ValueEnum;" déclare
que "Collection<>" récupère le type "ValueEnum" de la classe
"ValueTrait", mais je ne suis pas sûr qu'elle parle des _valeurs_ A,
B, etc.


--
;-)

Avatar
Pascal Béthune
Re,

Fabien LE LEZ wrote:
On Fri, 19 Nov 2004 22:54:41 +0100, Pascal Béthune :


extrait.cpp:37: error: `A' is not a member of type
`Collection<MyValueTrait>'



Est-ce une erreur, d'après toi ?

La ligne "typedef typename ValueTrait::ValueEnum ValueEnum;" déclare
que "Collection<>" récupère le type "ValueEnum" de la classe
"ValueTrait", mais je ne suis pas sûr qu'elle parle des _valeurs_ A,
B, etc.




C'est bien ce que je constate. Comment pourrait t-on faire pour
"importer" les valeurs dans la classe template pour "masquer" à
l'utilisateur l'existance de la classe MyValueTrait ?

-- Pascal


Avatar
Pascal Béthune
Pascal Béthune wrote:

C'est bien ce que je constate. Comment pourrait t-on faire pour
"importer" les valeurs dans la classe template pour "masquer" à
l'utilisateur l'existance de la classe MyValueTrait ?

-- Pascal


Mettre dans la classe template


typedef ValueTrait Access;


et à l'utilisation:


collection[ Collection< MyValueTrait >::Access::A ] = 3;


Mais je ne trouve pas ça très élégant. Quelqu'un a une autre idée ?

-- Pascal

Avatar
Fabien LE LEZ
On Fri, 19 Nov 2004 23:07:29 +0100, Pascal Béthune :

Comment pourrait t-on faire pour
"importer" les valeurs dans la classe template pour "masquer" à
l'utilisateur l'existance de la classe MyValueTrait ?


Déjà, il faudrait que tu expliques un peu plus clairement ta
problématique. Que représente exactement ton enum, et pourquoi est-il
dans le trait ?


--
;-)

Avatar
Pascal Béthune
Fabien LE LEZ wrote:
On Fri, 19 Nov 2004 23:07:29 +0100, Pascal Béthune :


Comment pourrait t-on faire pour
"importer" les valeurs dans la classe template pour "masquer" à
l'utilisateur l'existance de la classe MyValueTrait ?



Déjà, il faudrait que tu expliques un peu plus clairement ta
problématique. Que représente exactement ton enum, et pourquoi est-il
dans le trait ?




J'ai une classe de base polymorphique Value.

La classe template Collection a pour but de faire une collection de
dérivées de Value.

Chaque Collection à un nombre fini de Value (d'ou l'énuméré).

A la construction de la Collection, je souhaite contruire le bon objet
dont la classe est dérivé de Value, d'où la classe MyValueTrait qui
contient une fonction statique instanciateValue( enuméré) qui retourne
un Value* et qui alloue le bon objet en fonction de la valeur de
l'énuméré. instanceValue est utilisé par le constructeur de Collection.

La classe template Collection prend alors comme parametre la classe
MyValueTrait qui contient l'énuméré et la fonction instanciateValue qui
dépend fortement de cet énuméré.

Ce méchanisme fonctionne bien, seulement lors se l'utilisation de la
classe template Collection (une fois instanciée grace a la classe
MyValueTrait) on doit "encore" avoir connaisssance de MyValueTrait alors
que Collection< MyValueTrait> pourrait suffire il me semble. c-à-d:

si dans un fichier include on à:

typedef Collection< MyValueTrait > MyCollection;

et dans un autre fichier:

MyCollection collection;

collection.value[ MyValueTrait::A ] = 8;
// fonctionne mais laisse apparaitre MyValueTrait
// alors que MyValueTrait n'apparait pas dans le fichier

collection.value[ MyCollection::A ] = 8;
// ne fonctionne pas :(

collection.value[ MyCollection::Access::A ] = 8;
// fonctionne mais me parait plus lourd


Voila le contexte.

-- Pascal


Avatar
Fabien LE LEZ
On Fri, 19 Nov 2004 22:54:41 +0100, Pascal Béthune :

int & operator[]( ValueEnum valueEnum )
{
// source simplifié pour le post
return value_;


C'est bien joli de simplifier, mais là, c'est carrément incorrect : tu
renvoies une référence vers un objet qui ne survit pas à la fonction.


--
;-)

Avatar
Fabien LE LEZ
On Sat, 20 Nov 2004 00:11:23 +0100, Pascal Béthune :

on doit "encore" avoir connaisssance de MyValueTrait


En fait, ça ne me paraît pas un problème. Si le enum est spécifique au
trait, pour connaître les valeurs, on doit lire la déclaration de la
classe de trait. Donc, continuer à en parler ne me paraît pas
scandaleux.

Au fait, j'ai l'impression que tu mélanges allègrement deux formes de
polymorphisme : l'héritage et les templates. Si tu souhaites utiliser
des templates, tu n'as pas forcément besoin de polymorphisme
d'héritage, et vice-versa.


--
;-)

Avatar
Pascal Béthune
Fabien LE LEZ wrote:
On Fri, 19 Nov 2004 22:54:41 +0100, Pascal Béthune :


int & operator[]( ValueEnum valueEnum )
{
// source simplifié pour le post
return value_;



C'est bien joli de simplifier, mais là, c'est carrément incorrect : tu
renvoies une référence vers un objet qui ne survit pas à la fonction.




value_ est un attribut de la classe Collection. Donc le retour de
fonction survit à l'appel de fonction. (il ne s'agit pas d'une variable
locale).


-- Pascal


Avatar
Pascal Béthune
Fabien LE LEZ wrote:
On Sat, 20 Nov 2004 00:11:23 +0100, Pascal Béthune :


on doit "encore" avoir connaisssance de MyValueTrait



En fait, ça ne me paraît pas un problème. Si le enum est spécifique au
trait, pour connaître les valeurs, on doit lire la déclaration de la
classe de trait. Donc, continuer à en parler ne me paraît pas
scandaleux.

Au fait, j'ai l'impression que tu mélanges allègrement deux formes de
polymorphisme : l'héritage et les templates. Si tu souhaites utiliser
des templates, tu n'as pas forcément besoin de polymorphisme
d'héritage, et vice-versa.




non, je ne confond pas les 2. C'est bien un template puisque je veux
autant de collection que de type énumérés possible.

le polymorphique est sur Value. a chaque valeur d'un énuméré, j'associe
un type dérivé de Value. Par exemple Vitesse, Altitude, Coordonnees ...

exemple:

class InputTrait
{
public:
enum ValueType { VITESSE, ALTITUDE, COORDONNEE, END };

static Value * instanciateValue( ValueType valueType )
{
Value * value;
switch( valueType ) {
case VITESSE : value = new Vitesse ; break;
case ALTITUDE : value = new Altitude ; break;
case COORDONNEE: value = new Coordonnee; break;
default: assert( "XXXXX" ); }
return value;
}
};


template< class ValueTrait >
class Collection
{
Collection()
{
for( cpt = 0; ValueTrait::END; ++cpt )
{
values_[ cpt ] = ValueTrait::instanciateValue( cpt );
}
}

Value * values_[ ValueTrait::END ];
};

typedef Collection< InputTrait > InputCollection;


code non testé mais qui donne un aperçu du méchanisme.

-- Pascal


Avatar
Pascal Béthune
Fabien LE LEZ wrote:

on doit "encore" avoir connaisssance de MyValueTrait


En fait, ça ne me paraît pas un problème. Si le enum est spécifique au
trait, pour connaître les valeurs, on doit lire la déclaration de la
classe de trait. Donc, continuer à en parler ne me paraît pas
scandaleux.


Moi non plus, ça ne me parait pas scandaleux. C'est juste que je
souhaitais la "masquer" un peu vis à vis des utilisateurs de collection.
Peut être vais-je pouvoir remedier au problème en changeant le nommage
de la classe trait pour la rendre plus "présentable" aux utilisateurs de
collection.

l'orgine de mon post était plus la surprise concernant le comportement
de typdef qui importe le type énéuméré dans le scope de la classe
Collection sans amener les valeurs de cet énuméré.

-- Pascal


1 2