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

std_foreach et functor template

36 réponses
Avatar
jeremie fouche
Bonsoir

J'ai actuellement :

class C
{
private:
vector<Type*> m_vector;

public:
void clear(void)
{
for ( vector<Type*>::iterator i = m_vector.begin()
; i != m_vector.end()
; ++i
)
{
delete *i;
}
vector.clear();
}
};


je voulais changer le gros for en un std::for_each

1er essai :

void del(Type* ptr)
{
delete ptr;
}

void clear(void)
{
std::for_each(m_vector.begin(), m_vector.end(), del);
vector.clear();
}

Ca fonctionne !

2eme essai (car j'ai plusieurs conteneur de différent type) :

template <class T>
void del(T* ptr)
{
delete ptr;
}

void clear(void)
{
std::for_each(m_vector.begin(), m_vector.end(), del);
vector.clear();
}

Pouf, ca ne compile pas. Pourquoi la fonction template ne peut etre
créée pour la class Type* ?

Merci pour vos réponses
--
Jérémie

10 réponses

1 2 3 4
Avatar
Fabien LE LEZ
On Sat, 08 Dec 2007 19:09:16 +0100, jeremie fouche :

class C
{
private:
vector<Type*> m_vector;


Si tu mets ta classe dans un .h, évite d'utiliser "using namespace",
et écris std::vector<>

public:
void clear(void)


Attention, ça c'est du C. En C++ on écrira plutôt :
void clear()


2eme essai (car j'ai plusieurs conteneur de différent type) :

template <class T>
void del(T* ptr)
{
delete ptr;
}

void clear(void)
{
std::for_each(m_vector.begin(), m_vector.end(), del);


"del" n'est pas une fonction, c'est un template. En d'autres termes,
un truc qui n'a pas d'existence réelle tant qu'il n'est pas instancié.
Par contre, "del<Type>" est bien une fonction.
Tu peux donc écrire :

std::for_each(m_vector.begin(), m_vector.end(), del<Type>);

Avatar
jeremie fouche
On Sat, 08 Dec 2007 19:09:16 +0100, jeremie fouche :

vector<Type*> m_vector;


Si tu mets ta classe dans un .h, évite d'utiliser "using namespace",
et écris std::vector<>


Pas de pb, je ne le fais jamais, c'était pour (simplifier ?) l'exemple,
qui n'est pas un copier/coller de mon code.

public:
void clear(void)


Attention, ça c'est du C. En C++ on écrira plutôt :
void clear()


Tiens donc...
Ca, je le fais systématiquement afin d'améliorer la lisibilité (la
mienne en tout cas). Je n'ai jamais ne serait ce qu'un simple warning à
ce propos. Y a-t-il une raison pour ça ?

template <class T>
void del(T* ptr)
{
delete ptr;
}

void clear(void)
{
std::for_each(m_vector.begin(), m_vector.end(), del);



Ah, tu vois... le bô 'std::'

"del" n'est pas une fonction, c'est un template. En d'autres termes,
un truc qui n'a pas d'existence réelle tant qu'il n'est pas instancié.
Par contre, "del<Type>" est bien une fonction.
Tu peux donc écrire :

std::for_each(m_vector.begin(), m_vector.end(), del<Type>);


Bon sang mais c'est bien sûr !
Merci pour tout.
--
Jérémie


Avatar
Fabien LE LEZ
On Sat, 08 Dec 2007 22:09:49 +0100, jeremie fouche :

void clear(void)
Ca, je le fais systématiquement afin d'améliorer la lisibilité (la


mienne en tout cas).


Serais-tu un programmeur C converti au C++ ?

Je n'ai jamais ne serait ce qu'un simple warning à
ce propos.


Comme la plupart du code C, c'est du code C++ correct.
Toutefois, ce n'est pas idiomatique en C++. Du coup, le lecteur va se
demander pourquoi tu as écrit ça.

C'est un peu comme le passage d'arguments par référence constante : si
tu écris
void f (C un_objet);
le lecteur va buter sur le code, et se demander pourquoi tu ne suis
pas les conventions habituelles.



Avatar
James Kanze
On Dec 8, 10:09 pm, jeremie fouche wrote:

Attention, ça c'est du C. En C++ on écrira plutôt :
void clear()


Tiens donc...
Ca, je le fais systématiquement afin d'améliorer la lisibilité
(la mienne en tout cas).


Écrire qu'une fonction a un paramètre, alors qu'il n'en a pas,
améliore la lisibilité ? Il y a quelque chose que je ne
comprends pas.

Je n'ai jamais ne serait ce qu'un simple warning à ce propos.
Y a-t-il une raison pour ça ?


Historiquement, C++ a inventé les prototypes de fonctions, et
les a rendus obligatoire dès ses débuts : la seule écriture
légale était :
void clear() ;
En C, aussi, c'était la seule écriture légale, mais avec un
autre sémantique : ça signifiait qu'on ne donnait aucune
information en ce qui concerne les paramètres. (Je ne suis pas
sûr, mais je crois qu'on ne pouvait pas donner d'information
dans une declaration, seulement dans une définition.)

L'absence des prototypes était un très grand défaut de C (parmi
d'autres). Lors de la normalisation du langage, le comité ANSI a
donc adopté les prototypes de C++. Sans les rendre obligatoire,
en revanche, puisque ça aurait cassé tout programme existant. Du
coup, il y avait une ambiguïté :
void clear() ;
déclarait-il une fonction sans paramètres (ce qui aurait été
normal), ou une fonction dont on ne donnait pas d'information
sur les paramètres. Afin de ne pas casser le code existant (et
c'est bien la seule justification), le comité C a tranché pour
le seconde, et inventer l'écriture:
void clear( void ) ;
pour le premier. Ce n'a jamais été quelque chose qu'on voulait,
mais simplement un pis-aller, qui permettait l'introduction des
prototypes sans casser le code existant.

Ensuite, C++ a rendu cette écriture légale aussi, surtout afin
de supporter les en-têtes partagés, du genre :

#ifdef __cplusplus
extern "C" }
#endif

void someFunction( void ) ;

#ifdef __cplusplus
}
#endif

Ici aussi, ce n'est pas qu'on voulais de telle syntaxe, c'était
un compromis pour résoudre un problème pragmatique.

Maintenant, évidemment, on est formellement libre de faire ce
qu'on veut. Mais si on veut rester dans la philosophie générale
du language, telle qu'il a été conçu, cette utilisation très
particulière de void se limiterait aux cas où c'est nécessaire
pour des raisons de compatibilité C.

--
James Kanze (GABI Software) email:
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
espie
In article ,
James Kanze wrote:
Historiquement, C++ a inventé les prototypes de fonctions, et
les a rendus obligatoire dès ses débuts : la seule écriture
légale était :
void clear() ;
En C, aussi, c'était la seule écriture légale, mais avec un
autre sémantique : ça signifiait qu'on ne donnait aucune
information en ce qui concerne les paramètres. (Je ne suis pas
sûr, mais je crois qu'on ne pouvait pas donner d'information
dans une declaration, seulement dans une définition.)


Oui, C se comportait comme un assembleur: on declare juste qu'on utilise
des symboles, avec extremement peu de controle sur les symboles en question.

D'ailleurs, globalement, on utilise toujours des editeurs de lien de cette
epoque, d'ou le `name-mangling' pour encoder le typage des fonctions qui
est utilise par la plupart des implementations de C++.

En fait, les prototypes n'existaient pas du tout en C Kernighan et Richie,
y compris pour les definitions de fonctions, ou on ecrivait quelque chose
tel que:

f(a)
int a;
{
}

(en l'absence de void, une fonction telle que f etait reputee
`traditionnellement' ne renvoyer rien, le compilateur jetant un voile
pudique sur le `int' implicite)

Le passage au C ANSI ne s'est pas fait sans douleur, puisque les fonctions
sans prototypes avaient des regles differentes de coercion de type. Par
exemple, impossible de passer un char ou un float une fonction sans
prototype, les arguments etant d'office promu en int et double respectivement.

Ca a conduit a quelques-uns des pieges les plus vicieux du langage.
Ainsi, pour une definition de fonction en

f(a)
char a;
{
}


le prototype correspondant est bien
extern int f(int);

Ouch...

d'ou profonde rigolade lors de phases d'ansifications d'arbre source, vu
que le passage de l'un a l'autre n'est vraiment pas automatique.

et si on veut convertir *aussi* la definition de fonction, ca ne donne rien
de simple:

int
f(int a_)
{
char a = (char)a_;
}

Bref, le comite a essaye de casser les choses le moins possible tout en
modernisant fortement le langage... certaines des autres decisions (et
leurs applications) sont encore plus fourbes et ont poses encore plus
de problemes (confere toute la polemique autour de restrict, ou les decisions
de certains compilo `d'optimiser' les appels a memset qui `ne servent a rien')


[...]

Ton resume de la suite est correct, mais il y manque un element pedagogique.

C'est bien de permettre l'ecriture de void clear(void); en C++, ca permet
de simplifier les regles a retenir entre C et C++.

Meme si c'est pas `le plus propre' possible, je prefere dire aux gens
d'ecrire
void clear(void);
systematiquement, entre le C et le C++.
Tot ou tard, ils vont se retrouver a devoir utiliser les deux langages,
et cette syntaxe est la seule qui est sans surprise, et qui va fonctionner
sans devoir connaitre tous ces points de details obscurs...

Avatar
jeremie fouche
In article ,
James Kanze wrote:


plein de choses intéressantes...



Merci beaucoup pour vos réponses. J'aurais au moins appris plein de
choses ce week-end.
--
Jérémie


Avatar
Fabien LE LEZ
On Sun, 9 Dec 2007 12:59:48 +0000 (UTC), (Marc Espie):

Meme si c'est pas `le plus propre' possible, je prefere dire aux gens
d'ecrire
void clear(void);
systematiquement, entre le C et le C++.


Bof... Ça contribue à alimenter le mythe qu'il y a un rapport
privilégié entre le C++ et le C.

Tot ou tard, ils vont se retrouver a devoir utiliser les deux langages,


Pas forcément ces deux-là en particulier.
Un programmeur risque fort de rencontrer plusieurs langages
différents, mais un code donné est écrit dans un langage (même s'il
est facilement transcriptable dans un autre). Deux bouts de code
écrits dans deux langages différents (Java et Perl, C++ et C, etc.)
peuvent parfois communiquer, via une interface de communication
précise, mais il s'agit toujours de deux langages différents.

Avatar
espie
In article ,
Fabien LE LEZ wrote:
On Sun, 9 Dec 2007 12:59:48 +0000 (UTC), (Marc Espie):

Meme si c'est pas `le plus propre' possible, je prefere dire aux gens
d'ecrire
void clear(void);
systematiquement, entre le C et le C++.


Bof... Ça contribue à alimenter le mythe qu'il y a un rapport
privilégié entre le C++ et le C.


C'est pas un mythe !

Une des raisons d'utiliser ces deux langages, c'est l'enorme quantite
de code deja existant.

Ca serait meme une des plus grosses raisons aujourd'hui, vu la relative
complexite des deux langages par rapport a ce qu'ils permettent de
faire...


Avatar
Fabien LE LEZ
On Sun, 9 Dec 2007 22:08:14 +0000 (UTC), (Marc Espie):

Bof... Ça contribue à alimenter le mythe qu'il y a un rapport
privilégié entre le C++ et le C.


C'est pas un mythe !


Ah bon ?

Une des raisons d'utiliser ces deux langages, c'est l'enorme quantite
de code deja existant.


Il est vrai qu'en C++, on peut utiliser des bibliothèques écrites en
C. Mais ce n'est pas, il me semble, spécifique au C++ : on peut
accéder à des fonctions C, plus ou moins facilement, depuis pas mal de
langages. Y compris (feu ?) Visual Basic, d'ailleurs.

Ca serait meme une des plus grosses raisons aujourd'hui, vu la relative
complexite des deux langages par rapport a ce qu'ils permettent de
faire...


Uh ?

Le C est effectivement complexe et pauvre en fonctionnalités, mais est
très utilisé, peut-être parce que c'est une alternative portable à
l'assembleur (d'où son intérêt pour le noyau de Linux, par exemple).

Le C++ est complexe pour une toute autre raison : il a plus de
fonctionnalités que n'importe quel autre langage. À peu près tous les
paradigmes sont utilisables en C++ (même la programmation
fonctionnelle, avec les templates), ce qui donne une grande liberté,
mais aussi plus de responsabilités, au programmeur.


Avatar
Sylvain
Fabien LE LEZ wrote on 09/12/2007 23:48:
On Sun, 9 Dec 2007 22:08:14 +0000 (UTC), (Marc Espie):

Bof... Ça contribue à alimenter le mythe qu'il y a un rapport
privilégié entre le C++ et le C.
C'est pas un mythe !



Ah bon ?


il semble en effet.

Une des raisons d'utiliser ces deux langages, c'est l'enorme quantite
de code deja existant.


Il est vrai qu'en C++, on peut utiliser des bibliothèques écrites en
C. Mais ce n'est pas, il me semble, spécifique au C++ : on peut
accéder à des fonctions C, plus ou moins facilement, depuis pas mal de
langages. Y compris (feu ?) Visual Basic, d'ailleurs.


il me semble que Marc parlait de la réutilisation de code source (là où
on verrait un "foo(void)") pas de DLL spécifique MS vaguement parait-il
utilisable depuis un language spécifique MS, enfin il me semble ...

Sylvain.



1 2 3 4