OVH Cloud OVH Cloud

template et #define

19 réponses
Avatar
PurL
Bonjour,

je définis une fonction d'écriture de données dans un fichier et j'utilise
les templates pour pouvoir spécifier le type de la donnée à écrire :

template <class type> void WriteData(type data)
{
m_fichier->Write(&data, sizeof(type));
}

je l'utilise ainsi :

WriteData<int>(10);
WriteData<int>(ma_variable);

et ca marche bien.

Par contre je définis aussi :

#define ENTETE_VERSION 6

et quand je fais :

WriteData<int>(ENTETE_VERSION);

mon compilateur m'indique :
[C++ Erreur] UnitFichier.cpp(32): E2121 ) manquante dans l'appel de fonction
[C++ Erreur] UnitFichier.cpp(32): E2188 Syntaxe de l'expression

Pourquoi cette erreur ?

Merci,

Note : je suis sous BCB5

PurL.

9 réponses

1 2
Avatar
Brieuc Jeunhomme
Je crois que tu confonds avec des choses comme :

int i = 42 ;

void
f( int const& param )
{
std::cout << param << 'n' ;
++ i ;
std::cout << param << 'n' ;
++ const_cast< int& >( param ) ;
std::cout << param << 'n' ;
}


Ah non, il n'y a pas de risque, vu que j'ignore ce qu'est un const_cast.
La ligne avec le const_cast change quelque chose par rapport à
++ (int &) ( param ); ?

Au cours de mes essais, j'ai essayé de définir une variable const dans
un fichier et d'y accéder en la déclarant comme extern const dans un
autre. Ca passait à la compilation, mais pas à l'édition de liens...
const implique static ?

--
BBP

Avatar
Anthony Fleury
Brieuc Jeunhomme wrote:

Je crois que tu confonds avec des choses comme :

int i = 42 ;

void
f( int const& param )
{
std::cout << param << 'n' ;
++ i ;
std::cout << param << 'n' ;
++ const_cast< int& >( param ) ;
std::cout << param << 'n' ;
}


Ah non, il n'y a pas de risque, vu que j'ignore ce qu'est un const_cast.
La ligne avec le const_cast change quelque chose par rapport à
++ (int &) ( param ); ?


Ca revient au même. Par contre, const_cast<> est fait pour ce genre
d'utilisations (c'est un peu la même chose que la différence entre un
static_cast<> et un cast à la C). En fait, il est utilisé pour dire : "Je
sais que le paramètre qui m'est passé est constant, mais je veux le
modifier quand même."
Seulement, l'exemple de James a un comportement défini, mais ce n'est pas le
cas si la variable est *vraiment* constante :

const int i = 42;

void f(const int& p) {
++ const_cast< int& > (p);
}

int main() {
f(i);
}

Sur un vrai système d'exploitation, ce code affichera "Segmentation
Fault" (ou équivalent).

const_cast<> est donc utilisé pour enlever le caractère constant d'un
paramètre référence ou pointeur, afin de modifier l'objet référencé ou
pointé si celui ci n'est pas constant.


Au cours de mes essais, j'ai essayé de définir une variable const dans
un fichier et d'y accéder en la déclarant comme extern const dans un
autre. Ca passait à la compilation, mais pas à l'édition de liens...
const implique static ?



Par défaut, les variables déclarées en const ont un linkage interne. Il faut
donc écrire :

1.cpp

extern const int i = 42;

2.cpp :

#include <iostream>
extern const int i;

int main() {
std::cout << i << std::endl;
}

Anthony
--
It's a bird.. It's a plane..
No, it's KernelMan, faster than a speeding bullet, to your rescue.
Doing new kernel versions in under 5 seconds flat..
-- Linus, in the announcement for 1.3.27


Avatar
kanze
Brieuc Jeunhomme wrote in message
news:...

Je crois que tu confonds avec des choses comme :

int i = 42 ;

void
f( int const& param )
{
std::cout << param << 'n' ;
++ i ;
std::cout << param << 'n' ;
++ const_cast< int& >( param ) ;
std::cout << param << 'n' ;
}


Ah non, il n'y a pas de risque, vu que j'ignore ce qu'est un
const_cast. La ligne avec le const_cast change quelque chose par
rapport à ++ (int &) ( param ); ?


Dans ce cas-ci, non. L'avantage de const_cast, c'est que le compilateur
aurait hurlé si tu l'avait écrit « const_cast< double& > », tandis
qu'avec ta version, ç'aurait passé la compilation, mais aurait sans
doute donné des problèmes à l'execution.

Si tu voulais vraiment traiter des entiers en double, parce que par
exemple tu les a bien rempli en connaissant la représentation des
doubles, il y a un reinterpret_cast qui le permet. Mais tu risque pas de
le faire accidentalement avec const_cast, quand ton seul but était de
changer le const.

Au cours de mes essais, j'ai essayé de définir une variable const dans
un fichier et d'y accéder en la déclarant comme extern const dans un
autre. Ca passait à la compilation, mais pas à l'édition de liens...
const implique static ?


Pour Dieu sait quelle raison, oui, quand le const se trouve à la portée
de namespace. Pour contourner le problème, je précise toujours ou static
ou extern, par exemple :

static int const localInt = 42 ;
extern int const globalInt = 100 ;

Et dans le .hh :

extern int const globalInt ;

Ça me fait toujours drôle d'utiliser le mot clé « extern » pour une
définition, et non seulement pour une déclaration, mais c'est comme ça.
(C'est moins genant que d'appeler « remove » une fonction qui reordonne
un tableau sans rien enlever.)

--
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
Loïc Joly
wrote:

Ça me fait toujours drôle d'utiliser le mot clé « extern » pour une
définition, et non seulement pour une déclaration, mais c'est comme ça.
(C'est moins genant que d'appeler « remove » une fonction qui reordonne
un tableau sans rien enlever.)


Elle ne fait pas que réordonner, elle rend aussi les éléments "à la fin"
non valides. Mais effectivement, elle n'enlève pas vraiment.

--
Loïc

Avatar
Fabien LE LEZ
On Fri, 28 May 2004 19:08:09 +0200, "Alexandre"
wrote:

Mais en tout cas ni comme macros ni comme constantes..


Je ne sais plus si Sutter en parle, mais il me semble que le
préprocesseur est la seule possibilité pour faire en sorte que le code

int mon_entier= ...;
std::string une_chaine= ...;

MACRO_AFFICHE (mon_entier);
MACRO_AFFICHE (une_chaine);

balance ça sur la sortie standard :

Valeur de "mon_entier" : 42
Valeur de "une_chaine" : éléphant rose

Bon, évidemment, ça sert plus pour le débogage qu'en release... mais
le principe c'est que pour le compilo, mon_entier ne peut être qu'un
nombre, tandis que pour le préprocesseur, c'est une chaîne de
caractères -- il peut donc mettre des guillemets autour, puis la
ré-écrire à côté sans guillemets.

--
;-)
FLL, Epagneul Breton

Avatar
Loïc Joly
Fabien LE LEZ wrote:

On Fri, 28 May 2004 19:08:09 +0200, "Alexandre"
wrote:


Mais en tout cas ni comme macros ni comme constantes..



Je ne sais plus si Sutter en parle, mais il me semble que le
préprocesseur est la seule possibilité pour faire en sorte que le code

int mon_entier= ...;
std::string une_chaine= ...;

MACRO_AFFICHE (mon_entier);
MACRO_AFFICHE (une_chaine);

balance ça sur la sortie standard :

Valeur de "mon_entier" : 42
Valeur de "une_chaine" : éléphant rose


Il en parle :
2. Accessing Preprocessor Features

It's often nice to insert things like line numbers and build times in
diagnostic code. An easy way to do this is to use predefined macros like
__FILE__, __LINE__, __DATE__ and __TIME__. For the same and other
reasons, it's often useful to use the stringizing and token-pasting
preprocessor operators (# and ##).

--
Loïc


Avatar
kanze
Loïc Joly wrote in message
news:<c9l4p1$dad$...
wrote:

Ça me fait toujours drôle d'utiliser le mot clé « extern » pour une
définition, et non seulement pour une déclaration, mais c'est comme
ça. (C'est moins genant que d'appeler « remove » une fonction qui
reordonne un tableau sans rien enlever.)


Elle ne fait pas que réordonner, elle rend aussi les éléments "à la
fin" non valides. Mais effectivement, elle n'enlève pas vraiment.


Comment ça, non valide. Leurs valeurs ne sont pas spécifiées, mais ils
restent toujours valides, j'espère. La présence d'un objet non valide
dans une collection standard est un comportement indéfini.

Le tout selon la norme, évidemment.

--
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
Loïc Joly
wrote:

Loïc Joly wrote in message
news:<c9l4p1$dad$...

wrote:



Ça me fait toujours drôle d'utiliser le mot clé « extern » pour une
définition, et non seulement pour une déclaration, mais c'est comme
ça. (C'est moins genant que d'appeler « remove » une fonction qui
reordonne un tableau sans rien enlever.)




Elle ne fait pas que réordonner, elle rend aussi les éléments "à la
fin" non valides. Mais effectivement, elle n'enlève pas vraiment.



Comment ça, non valide. Leurs valeurs ne sont pas spécifiées, mais ils
restent toujours valides, j'espère.


J'insistait surtout sur la phrase comme quoi rien n'est enlevé. remove
peut très bien enlever certains des éléments concernés, tous, aucun,
créer de nouveaux éléments (là, je suis pas 100% sur... un algo qui
créerait des objets pour les types default constructible et en
dupliquerait pour les autres serait-il valide ?),...


La présence d'un objet non valide
dans une collection standard est un comportement indéfini.

Le tout selon la norme, évidemment.


Effectivement, les objets en question sont toujours valides, mais on ne
peut rien dire de ce qu'ils valent.

--
Loïc



Avatar
James Kanze
Loïc Joly writes:

|> wrote:

|> > Loïc Joly wrote in message
|> > news:<c9l4p1$dad$...

|> >> wrote:

|> >>>Ça me fait toujours drôle d'utiliser le mot clé « extern » pour
|> >>>une définition, et non seulement pour une déclaration, mais c'est
|> >>>comme ça. (C'est moins genant que d'appeler « remove » une
|> >>>fonction qui reordonne un tableau sans rien enlever.)

|> >>Elle ne fait pas que réordonner, elle rend aussi les éléments "à
|> >>la fin" non valides. Mais effectivement, elle n'enlève pas
|> >>vraiment.

|> > Comment ça, non valide. Leurs valeurs ne sont pas spécifiées, mais
|> > ils restent toujours valides, j'espère.

|> J'insistait surtout sur la phrase comme quoi rien n'est enlevé.

C-à-d que remove ne laisse pas forcement une permutation de la suite
initiale. C'est vrai. Ça peut être un peu plus que simplement
réordonner. Mais c'est encore loin d'« enlever ».

|> remove peut très bien enlever certains des éléments concernés, tous,
|> aucun, créer de nouveaux éléments (là, je suis pas 100% sur... un
|> algo qui créerait des objets pour les types default constructible et
|> en dupliquerait pour les autres serait-il valide ?),...

Probablement. En fait : remove ne peut pas enlever d'éléments. Il peut
en changer la valeur. En fait, il ne peut qu'en changer la valeur. Après
remove, il est garanti que la sous-suite en tête de la suite contient
toutes les valeurs pour lesquelles la condition était fausse, dans leur
ordre original, et seulement ses valeurs. Et que les valeurs de la
sous-suite à la fin ne sont pas spécifiées.

Mais tous les éléments y sont. Avec des valeurs modifiées, mais ils y
sont, et ils sont tous valide (parce que les fonctions de la STL ne
savent pas rendre une valeur invalide sans l'enlever de la suite).

Un élément invalid, c'est par exemple un pointeur après un delete.
Remove ne fait rien comme ça. S'il le faisait, on ne pourrait plus
emlever les éléments de la deuxième sous-suite. Ni même détruire la
collection. Selon la norme, s'entend, parce que dans la réalité...

|> > La présence d'un objet non valide dans une collection standard est
|> > un comportement indéfini. Le tout selon la norme, évidemment.

|> Effectivement, les objets en question sont toujours valides, mais on
|> ne peut rien dire de ce qu'ils valent.

Donc, le mot « remove » signifie réordonner et changer les valeurs des
éléments. Selon la norme C++, non selon les dictionnaires anglais dont
je dispose:-).

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