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

template et donnée membre static

6 réponses
Avatar
MGN
bonjour,
j'ai défini un patron de classe CVar<T> et je veux m'assurer que dans toutes
les implémentations, la classe T fournie en paramètre dérive d'une même
classe CTypeRoot.
Evidement, je peux vérifier que c'est bien le cas dans n'importe quel
constructeur.
Aussi je me suis dit : je vais introduire une donnée membre privée static
que j'initialise avec un appel de constructeur spécifique qui teste que
c'est le cas. Ce qui doit me permettre de détecter l'erreur au lancement du
programme, et pas à l'exécution (enfin, c'est mon but)

Mais avec mon compilateur, ça marche pas, ie la donnée membre static n'est
jamais initialisée...
Voilà le code simplifié :


/*export*/ template <class T>
class CVar : public CObjet
{

private :

inline CVar();
static CVar<T> *var_test; // ça ne marche pas


protected :
public :

inline CVar(const std::string&) ;

};

template <class T>
CVar<T> *CVar<T>::var_test=new CVar<T>::CVar<T>(); // initialisation de
le donnée membre static

template <class T>
inline CVar<T>::CVar()
{
if (!dynamic_cast<CTypeRoot*>(&T())) throw CException("problème !");
}

Est-ce que vous voyez où est l'erreur ?
Quand j'exécute le programme, la donnée membre static n'est jamais
initialisée....
merci de votre aide
Marc

6 réponses

Avatar
Anthony Fleury
bonjour,


Bonjour,

[...]

Mais avec mon compilateur, ça marche pas, ie la donnée membre static n'est
jamais initialisée...
Voilà le code simplifié :

/*export*/ template <class T>
class CVar : public CObjet
{
private :
inline CVar();
static CVar<T> *var_test; // ça ne marche pas
protected :
public :
inline CVar(const std::string&) ;
};

template <class T>
CVar<T> *CVar<T>::var_test=new CVar<T>::CVar<T>(); // initialisation de
le donnée membre static


Cette ligne compile avec le compilateur en question ? Parce que
CVar<T>::CVar<T>() n'est pas un type.

Donc :
template <class T> CVar<T> *CVar<T>::var_test = new CVar<T>;

Fonctionne chez moi et initialise bien une donnée membre static.

Est-ce que vous voyez où est l'erreur ?
Quand j'exécute le programme, la donnée membre static n'est jamais
initialisée....


Ca ne devrait pas compiler pour moi...

Par contre, est-ce un problème simplifié ou non ? En gros, y a-t-il un
seul type CTypeRoot duquel toutes les classes T doivent dériver ? Si
oui, pourquoi ne pas surcharger le constructeur de CVar pour le type
CTypeRoot& (donc spécialisation du template), et refuser la construction
dans le constructeur par défaut ?

--
Anthony Fleury

Avatar
Eric Pruneau
"MGN" a écrit dans le message de news:
437adc9c$0$19713$
bonjour,
j'ai défini un patron de classe CVar<T> et je veux m'assurer que dans
toutes les implémentations, la classe T fournie en paramètre dérive d'une
même classe CTypeRoot.


Donc tu veux vérifier que T hérite de CTypeRoot.
Tu peux faire ce check au moment de la compilation.
Donc si ce n'est pas le cas, ton programme ne compileras pas.
Le livre Modern C++ Design de Andrei Alexandrescu
donne la solution. Ce même auteur à développé Loki
http://sourceforge.net/projects/loki-lib/

Tu y trouveras dans le fichier TypeManip.h tout ce qu'il te faut

La seule chose que tu as a faire est d'utiliser la macro:
SUPERSUBCLASS(T,U)
Cette macro retourne true si T est une base publique de U.

Maintenant tu peux utiliser le résultat avec un BOOST_STATIC_ASSERT
http://www.boost.org/doc/html/boost_staticassert.html
le même genre de méchanisme est aussi dans loki mais la doc de ce dernier
lien
est plus intéressante...

donc ton programme va ressembler à :

template <class T>
class CVar : public CObjet
{
public:
CVar()
{
BOOST_STATIC_ASSERT( SUPERSUBCLASS(CTypeRoot,T) )
...
}
....
};

Voilà!
Toute tentative d'utiliser le constructeur avec un T qui n'hérite pas de
CTypeRoot produira un erreur de compilation!

Si tu n'en crois pas tes yeux, alors je te conseille le livre Modern C++
Desing

Eric

Avatar
MGN
Merci pour ta réponse.
J'ai téléchargé loki et il me reste à étudier TypeManip.h
Mais est-ce que tu comprends pourquoi mon code ne marche pas ? J'ai cru voir
dans loki qu'il utilisait également une donnée membre static pour provoquer
le test...

Marc
Avatar
Anthony Fleury
bonjour,


Bonjour,
J'avais déjà envoyé un article avec les choses que je vais noter ci
dessous, mais j'ai annulé car la fin du message était fausse, et je ne
comprend pas pourquoi, ca me fera l'occasion de poser une question dans
la journée si je ne trouve pas.

Pour ce qui est des explications sur comment faire un contrôle de type,
voir le post d'Eric Pruneau.

Mais avec mon compilateur, ça marche pas, ie la donnée membre static n'est
jamais initialisée...


Quel est le compilateur en question ? Et le code ci-dessous est-il le
vrai code compilé ? Car...

/*export*/ template <class T>
class CVar : public CObjet
{
private :
inline CVar();
static CVar<T> *var_test; // ça ne marche pas
protected :
public :
inline CVar(const std::string&) ;
};

template <class T>
CVar<T> *CVar<T>::var_test=new CVar<T>::CVar<T>(); // initialisation de
le donnée membre static


Ici ce code est invalide, car `CVar<T>::CVar<T>()` n'est pas un « type
specifier ».

Avec :
CVar<T> *CVar<T>::var_test=new CVar<T>;

Ca fonctionne.

Est-ce que vous voyez où est l'erreur ?
Quand j'exécute le programme, la donnée membre static n'est jamais
initialisée....


Comment est-ce vérifié ? à coup de gdb ?

Ici avec un code simplifié :

#include <iostream>

template <class T>
class A {
public:
static A<T>* add;
int a;
A(int a = 0):a(a) { }
};

template <class T> A<T>* A<T>::add = new A<T>(42);

int main() {
std::cout << A< int >::add->a << std::endl;
}

m'affiche bien 42 et ne provoque aucune erreur.

--
Anthony Fleury

Avatar
Franck Branjonneau
"MGN" écrivait:

j'ai défini un patron de classe CVar<T> et je veux m'assurer que dans toutes
les implémentations, la classe T fournie en paramètre dérive d'une même
classe CTypeRoot.

Mais avec mon compilateur, ça marche pas, ie la donnée membre static n'est
jamais initialisée...

/*export*/ template <class T>
class CVar : public CObjet
{

private :

inline CVar();
static CVar<T> *var_test; // ça ne marche pas


protected :
public :

inline CVar(const std::string&) ;

};

template <class T>
CVar<T> *CVar<T>::var_test=new CVar<T>::CVar<T>(); // initialisation de
le donnée membre static

template <class T>
inline CVar<T>::CVar()
{
if (!dynamic_cast<CTypeRoot*>(&T())) throw CException("problème !");
}


Pourquoi faire un dynamic_cast sur des pointeurs si c'est pour jeter
une exception ?

Si exception il y a, tu espères l'attraper ?

Ta condition me semble inadéquate, je me trompes ?

Est-ce que vous voyez où est l'erreur ?


Si ta variable n'est pas initialisée c'est parce qu'elle n'est pas
utilisée, c'est une particularité des templates.

--
Franck Branjonneau

Avatar
kanze
Franck Branjonneau wrote:
"MGN" écrivait:

j'ai défini un patron de classe CVar<T> et je veux m'assurer que dans toutes
template <class T>
CVar<T> *CVar<T>::var_test=new CVar<T>::CVar<T>(); // initialisat ion de
le donnée membre static

template <class T>
inline CVar<T>::CVar()
{
if (!dynamic_cast<CTypeRoot*>(&T())) throw CException("problè me !");



Je ne l'avais pas remarqué avant, mais cette ligne ne doit pas
se compiler. Si le template est instancié, en tout cas.
L'expression « T() » est un rvalue ; on ne peut donc pas en
prendre l'adresse. (Il y a une petite exception : si la classe T
rédéfinit l'opérateur & unaire.)

}


Pourquoi faire un dynamic_cast sur des pointeurs si c'est pour
jeter une exception ?

Si exception il y a, tu espères l'attraper ?

Ta condition me semble inadéquate, je me trompes ?


J'imagine que ce qu'il veut, c'est quelque chose come :

TypeRoot* p = static_cast< T* >( NULL ) ;

Si T ne dérive pas de TypeRoot, il y a une erreur de
compilation.

Est-ce que vous voyez où est l'erreur ?


Si ta variable n'est pas initialisée c'est parce qu'elle n'est
pas utilisée, c'est une particularité des templates.


Et si elle était utiliser, et donc instancié, il y aurait une
erreur de compilation.

--
James Kanze GABI Software
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