OVH Cloud OVH Cloud

Pbl template / définition de statique

17 réponses
Avatar
TjB
Bonjour,

Encore des soucis avec des templates avec le compilo g++. Le code
suivant ne passe pas du tout :
// -----------------------------
template <class T>
class toto {
toto() {}
~toto() {}
private:
static T a;
};

int toto<int>::a=3D4;
//------------------------------

L'erreur de compilation =E9tant "error: too few
template-parameter-lists", ce que je ne trouve pas tr=E8s explicite.
Bien s=FBr, si l'on n'est pas dans un cas "template", le code
fonctionne.

Que cette erreur signifie-t-elle ? Quelle devrait-=EAtre l'=E9criture
correcte ?

Par avance merci pour toute id=E9e.

T=2E
---
APC / IN2P3 / Universit=E9 Paris 7
http://apc-p7.org/~beau

10 réponses

1 2
Avatar
Sylvain
TjB wrote on 26/04/2006 21:40:

template <class T> class toto {
};

int toto<int>::a=4;

L'erreur de compilation étant "error: too few
template-parameter-lists", ce que je ne trouve pas très explicite.
Bien sûr, si l'on n'est pas dans un cas "template", le code
fonctionne.


oui je pense aussi que "int a = 4;" fonctionne.

à défaut d'une réponse à votre question, il y a une autre question à
laquelle je ne trouve pas de réponses: quel serait l'intérêt d'une
classe template basée sur un type primitif ?

rationale: 90% des codes utilisent "int" sans jamais se soucier de la
taille réelle (16, 32, 64?) des variables créées et quand bien même on
voudrait (hors structure à alignement fixe) utiliser une seule taille,
s'aligner sur la taille des registres fait sens. dès lors, il ne (me)
semble pas probable de rencontrer (d'avoir besoin) des toto<unsigned
char> ni des toto<signed long long>.

quelqu'un pour éclairer ma lanterne ?

Sylvain.

Avatar
TjB
Oui, je pense que le "int a = 4;" fonctionne.
Mon "vrai" problème c'est qu'il s'agissait en fait d'initialiser un
tableau, ce qui ne peut se faire dans la définition de classe.

En outre, entre temps, j'ai trouvé l'écriture qui convient :

template<> int toto<int>::a = 4;

Sinon, pas déclairage particulier sur votre question...

T.
Avatar
Sylvain
TjB wrote on 26/04/2006 22:07:
Oui, je pense que le "int a = 4;" fonctionne.
Mon "vrai" problème c'est qu'il s'agissait en fait d'initialiser un
tableau, ce qui ne peut se faire dans la définition de classe.

Sinon, pas déclairage particulier sur votre question...

zut alors, parce que moi j'avais bien un int* a = new int[N]; pour votre

problème de tableau ;)

j'ironise un peu bien sur! j'utilise plutot une classe "tableau
dynamique" avec redimensionnement, et tout le toutim, mais je reste
dubitatif pour son nécessaire(?) templatisation.

Sylvain.

Avatar
Sylvain
TjB wrote on 26/04/2006 22:07:

Mon "vrai" problème c'est qu'il s'agissait en fait d'initialiser un
tableau, ce qui ne peut se faire dans la définition de classe.


je ne comprends pas votre point!
quelle initialisation est impossible?

cela m'intéresse de comprendre si l'impossibilité est perçue comme
algorithmique - si c'est une impossibilité d'écrire du à la syntaxe des
classes templates, oubliez.

Sylvain.

Avatar
TjB
Non, je veux dire que l'écriture

//------------------------
class toto {
static const int machin[3]={0,1,2};
};
//------------------------

est invalide. Sans que les templates n'aient à intervenir. Il faut
passer, autant que je sache, par une écriture :
//------------------------
class toto {
static const int machin[3];
};

const int toto::machin[3]={0,1,2};
//-------------------------

Mais je dois avouer que je ne vois pas de bonne raison à ce
comportement...

T.
Avatar
Sylvain
TjB wrote on 26/04/2006 23:10:

class toto {
static const int machin[3]={0,1,2};
};
est invalide. [...]
Mais je dois avouer que je ne vois pas de bonne raison à ce
comportement...


au moins le fait qu'une déclaration de classe n'est pas censé réserver
spontanément de la mémoire.

cette classe peut ne jamais être instanciée (les 3 ints ne devront pas
être réservés) comme sa définition peut être incluse par plein de cpp,
lequel provoquerait la réservation mémoire ? le méta-runtime alimenté de
plein d'info RTTI étendue ? en Java ou en sharpouille pourquoi pas, mais
pas avec notre si bô langage en effet.

Sylvain.

Avatar
kanze
TjB wrote:
Encore des soucis avec des templates avec le compilo g++. Le code
suivant ne passe pas du tout :

// -----------------------------
template <class T>
class toto {
toto() {}
~toto() {}
private:
static T a;
};

int toto<int>::a=4;
//------------------------------

L'erreur de compilation étant "error: too few
template-parameter-lists", ce que je ne trouve pas très explicite.
Bien sûr, si l'on n'est pas dans un cas "template", le code
fonctionne.

Que cette erreur signifie-t-elle ? Quelle devrait-être l'écriture
correcte ?


On ne dévinera certainement pas d'après le message d'erreur:-),
mais le problème, c'est que tu n'as pas dit que la définition de
toto<int>::a était un template, ni qu'elle était une
spécialisation explicite d'un template. Selon le cas, il faut
écrire :
template< typename T >
T Toto< T >::titi = 0 ;
(définition générale), ou
template<>
int Toto< int >::titi = 4 ;
(spécialisation explicite pour int).

Attention, en revanche, avec la spécialisation explicite. Si je
ne me trompe pas, une spécialisation explicite n'est pas un
template, et ne doit être donc définie que dans une seule unité
de compilation. Mettre
template<>
int Toto< int >::titi = 4 ;
dans un en-tête, et l'inclure dans plusieurs unités de
compilation, aurait donc un comportement indéfini, et pourrait
bien provoquer des erreurs dues aux multiples définitions lors
de l'édition de liens. (C'est bien le cas avec g++ sous Solaris,
par exemple.) Il faudrait donc écrire :
template<>
extern int Toto< int >::titi ;
dans le fichier d'en-tête, et mettre la définition dans un seul
fichier source. Sauf que je ne sais pas si c'est standard, ou
une extention de g++ ; Sun CC le rejette en disant que extern
n'est pas permis ici. Mais sans la declaration de la
spécialisation explicite, tu aurais encore un comportement
indéfini si jamais tu utilises la variable en dehors de l'unité
de compilation où il a été definie.

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

Avatar
kanze
Sylvain wrote:

à défaut d'une réponse à votre question, il y a une autre
question à laquelle je ne trouve pas de réponses: quel serait
l'intérêt d'une classe template basée sur un type primitif ?


Tu ne vois pas l'intérêt d'un std::vector<int> de temps en
temps@? Ou d'un std::basic_string< char > ?

rationale: 90% des codes utilisent "int" sans jamais se
soucier de la taille réelle (16, 32, 64?) des variables créées
et quand bien même on voudrait (hors structure à alignement
fixe) utiliser une seule taille, s'aligner sur la taille des
registres fait sens. dès lors, il ne (me) semble pas probable
de rencontrer (d'avoir besoin) des toto<unsigned char> ni des
toto<signed long long>.


D'accord dans l'ensemble, mais il y a bien des exceptions : il
m'arrive d'utiliser size_t, time_t ou off_t, par exemple (et
aucun n'est un int.) Sans parler de char:-). (Et unsigned char
pour la mémoire brute, et des types unsigned quand je manipule
des bits. Mais ce sont des utilisations de bas niveau, qui ne
concernent pas la plupart des programmeurs.)

En fait, il m'arrive de les utiliser des non-signés (surtout
size_t) plus souvent que je ne veux. Parce que d'autres n'ont
pas suivi tes conseils, et se sont servi des types non-signés,
et qu'il vaut mieux éviter des mélanges de signés et de
non-signés.

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

Avatar
Sylvain
kanze wrote on 27/04/2006 11:09:
Sylvain wrote:

l'intérêt d'une classe template basée sur un type primitif ?


Tu ne vois pas l'intérêt d'un std::vector<int> de temps en
temps@? Ou d'un std::basic_string< char > ?


tu prends ma question de manière restrictive:
je n'ai pas dit que "std::vector<int>" ne servait pas, j'ai demandé si
pratiquement (ie dans la plupart des cas d'une appli réelle), on avait
besoin d'un std::vector<int> et d'un std::vector<short> (et d'un ...).

D'accord dans l'ensemble, mais il y a bien des exceptions : il
m'arrive d'utiliser size_t, time_t ou off_t, par exemple (et
aucun n'est un int.) Sans parler de char:-). (Et unsigned char
pour la mémoire brute, et des types unsigned quand je manipule
des bits. Mais ce sont des utilisations de bas niveau, qui ne
concernent pas la plupart des programmeurs.)


ok, pour ce point, string.h utilise largement size_t par exemple donc
bien sur qu'il sert - comme pour du bas niveau qu'un sale type osant
utiliser des shifts s'autorise sans scrupule - mais utilises-tu souvent
des vecteurs de time_t ? (c'est p.e. un mauvais exemple d'ailleurs).

En fait, il m'arrive de les utiliser des non-signés (surtout
size_t) plus souvent que je ne veux. Parce que d'autres n'ont
pas suivi tes conseils, et se sont servi des types non-signés,
et qu'il vaut mieux éviter des mélanges de signés et de
non-signés.


?!? je n'ai pas conseillé de ne pas utiliser d'unsigned - pour ma part
et dans nombre de cas je n'utilise "int" que comme variable de boucle et
plutot des short ou des long généralement unsigned ailleurs (mais ce
n'est que cas particulier pour des codes précis, ça ne fait ps une règle).

Sylvain.


Avatar
kanze
Sylvain wrote:
kanze wrote on 27/04/2006 11:09:
Sylvain wrote:

l'intérêt d'une classe template basée sur un type primitif ?


Tu ne vois pas l'intérêt d'un std::vector<int> de temps en
temps ? Ou d'un std::basic_string< char > ?


tu prends ma question de manière restrictive:
je n'ai pas dit que "std::vector<int>" ne servait pas, j'ai
demandé si pratiquement (ie dans la plupart des cas d'une
appli réelle), on avait besoin d'un std::vector<int> et d'un
std::vector<short> (et d'un ...).


Mais alors... Il n'a jamais dit que son template ne servait que
pour les types entiers de base -- je suis d'accord qu'écrire un
template qui n'accepte que les types entiers de base comme
paramètre, c'est vraiement rarement utile. (Sauf, peut-être,
pour rouler la mechanique. La mode est aux templates, après
tout, et si tu ne fais pas un template de tout, tu n'es pas in.)

D'accord dans l'ensemble, mais il y a bien des exceptions :
il m'arrive d'utiliser size_t, time_t ou off_t, par exemple
(et aucun n'est un int.) Sans parler de char:-). (Et
unsigned char pour la mémoire brute, et des types unsigned
quand je manipule des bits. Mais ce sont des utilisations de
bas niveau, qui ne concernent pas la plupart des
programmeurs.)


ok, pour ce point, string.h utilise largement size_t par
exemple donc bien sur qu'il sert - comme pour du bas niveau
qu'un sale type osant utiliser des shifts s'autorise sans
scrupule - mais utilises-tu souvent des vecteurs de time_t ?
(c'est p.e. un mauvais exemple d'ailleurs).


Parfois, mais c'est vrai que la plupart de mes vectors sont ou
des pointeurs, ou des classes. Mais je verrais bien un vector<
off_t > dans certains cas. Et quant aux autres templates :
pourquoi pas un std::map< EventId, time_t >, où EventId n'est
qu'un typedef à un type entier de base ?

En fait, il m'arrive de les utiliser des non-signés (surtout
size_t) plus souvent que je ne veux. Parce que d'autres
n'ont pas suivi tes conseils, et se sont servi des types
non-signés, et qu'il vaut mieux éviter des mélanges de
signés et de non-signés.


?!? je n'ai pas conseillé de ne pas utiliser d'unsigned


Ah bon. J'avais compris que tu conseillais int dans tous les cas
où il n'y avait pas d'impératif absolu d'un autre type (entier,
s'entend). C'est à peu près mon avis -- 9 fois sur 10, je n'y
reflechis même pas.

- pour ma part et dans nombre de cas je n'utilise "int" que
comme variable de boucle et plutot des short ou des long
généralement unsigned ailleurs (mais ce n'est que cas
particulier pour des codes précis, ça ne fait ps une règle).


Il y a des fois que d'autres types s'imposent -- j'ai aussi du
code avec les uint32_t, par exemple (dans l'implémentation de
SHA-1, par exemple). Mais ce sont des exceptions. (Il y a aussi
des décalages dans l'implémentation de SHA-1:-).)

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



1 2