OVH Cloud OVH Cloud

Yet another question sur friend et template...

15 réponses
Avatar
Jaco
Bonjour,

Moi aussi je me remet doucement =E0 C++... j'avais d=E9j=E0 un peu de mal =
=E0
l'=E9poque avec les templates et les friends et =E7a ne s'est pas
arrang=E9 !

Si je prend ce programme "jouet" suivant :

#include <iostream>
using namespace std;

const int TailleDefaut =3D 10;

class Animal {
public:
Animal(int);
Animal();
~Animal() {}
int GetPoids() const { return sonPoids; }
void Affiche() const { cout << sonPoids; }
private:
int sonPoids;
};

Animal::Animal(int poids): sonPoids(poids) {}

Animal::Animal(): sonPoids(0) {}

template <class T>
class Array {
public:
Array(int taille =3D TailleDefaut);
Array(const Array &rhs);
~Array() { delete [] pType; }

Array& operator=3D(const Array&);
T& operator[](int indice) { return pType[indice]; }
const T& operator[](int indice) const { return pType
[indice]; }

int GetTaille() const { return saTaille; }
friend ostream& operator<<(ostream&, Array<T>&);

private:
T *pType;
int saTaille;
};

// Impl=E9mentations...

template <class T>
Array<T>::Array(int taille): saTaille(taille) {
pType =3D new T[taille];
for (int i =3D 0; i < taille; i++)
pType[i] =3D 0;
}

template <class T>
Array<T>::Array(const Array &rhs) {
saTaille =3D rhs.GetTaille();
pType =3D new T[saTaille];
for (int i =3D 0; i < saTaille; i++)
pType[i] =3D rhs[i];
}

template <class T>
Array<T>& Array<T>::operator=3D(const Array &rhs) {
if (this =3D=3D &rhs)
return *this;
delete [] pType;
saTaille =3D rhs.GetTaille();
pType =3D new T[saTaille];
for (int i =3D 0; i < saTaille; i++)
pType[i] =3D rhs[i];
return *this;
}

template <class T>
ostream& operator<<(ostream& sortie, Array<T>& unTableau) {
for (int i =3D 0; i < unTableau.saTaille; i++)
sortie << "[" << i << "] " << unTableau[i] << endl;
return sortie;
}

int main() {
int indice, valeur;
Array<int> leTableau ;

while (true) {
cout << "Entrez un indice (0-9) ";
cout << "et une valeur. (-1 pour arr=EAter) : ";
cin >> indice >> valeur;

if (indice < 0)
break;

if (indice > 9) {
cout << "Entrez une valeur entre 0 et 9.\n";
continue;
}

leTableau[indice] =3D valeur;
}

cout << "\nVoici le tableau complet :\n";
cout << leTableau << endl;
return 0;
}

Et que je tente de le compiler avec g++-4.0, j'obtiens =E7a :

% g++ listing19_4.cpp
listing19_4.cpp:33: warning: friend declaration 'std::ostream&
operator<<(std::ostream&, Array<T>&)' declares a non-template function
listing19_4.cpp:33: warning: (if this is not what you intended, make
sure the function template has already been declared and add <> after
the function name here) -Wno-non-template-friend disables this warning
Undefined symbols:
"operator<<(std::basic_ostream<char, std::char_traits<char> >&,
Array<int>&)", referenced from:
_main in cciJyZWs.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
%

Le message du compilo m'indique bien qu'il y a un pb avec ma
d=E9claration de friend... mais j'avoue que je s=E8che... Une piste ?

Cordialement

5 réponses

1 2
Avatar
Fabien LE LEZ
On Sat, 21 Mar 2009 17:23:06 -0700 (PDT), Jaco
:

listing19_4.cpp:33: warning: (if this is not what you intended, make
sure the function template has already been declared



Ça, ça veut dire qu'il faut déclarer ta fonction avant de l'indiquer
comme "friend".

Donc, rajouter ces deux lignes avant "template <class T> class Array"

template <class T> class Array;
template <class T> ostream& operator<<(ostream&, Array<T>&);

and add <> after
the function name here)



Ça, ça signifie qu'il faut ajouter "<>" après le nom de la fonction.

friend ostream& operator<< <> (ostream&, Array<T>&);
Avatar
Eric Jacoboni
Fabien LE LEZ writes:

Ça, ça veut dire qu'il faut déclarer ta fonction avant de l'indiquer
comme "friend".



Ok, donc c'est ça que je n'avais pas compris : je pensais que la
déclaration de la fonction friend dans la classe template suffisait à ce
que le compilo comprenne ce que je voulais faire...

En tous cas, merci...
Avatar
Fabien LE LEZ
On Sun, 22 Mar 2009 17:01:40 +0100, Eric Jacoboni :

je pensais que la
déclaration de la fonction friend dans la classe template suffisait à ce
que le compilo comprenne ce que je voulais faire...



D'une manière générale, si tu veux qu'une fonction soit amie d'une
classe (ce que je ne conseille pas forcément), il vaut mieux la
déclarer avant la définition de la classe, puis l'indiquer comme amie
dans la classe. Ça évite bien des surprises.
Avatar
James Kanze
On Mar 22, 1:15 pm, Merwin wrote:
James Kanze a écrit :



[...]
Au niveau du temps d'éxécution, les fonctions inline ne sont
elles pas plus rapide?



Ça dépend du compilateur, et des options de compilation.
Certains compilateurs (g++, par exemple), l'ignore complètement
(sauf dans la mesure, évidemment, qu'il permet mettre la
définition dans toutes les unités de compilation). Et il arrive
dans des cas particuliers, l'inline rallentit le code.

Vue l'augmentation du couplage qu'il impose, j'évite l'inline en
général. En revanche, si j'ai un problème de performance, je
pourrais bien y recourir, en faisant des mesures -- s'il
apporte la performance voulue, c'est toujours un moindre mal que
de réécrire la fonction en me servant des algorithmes plus
compliqués. Souvent, si la performance n'y est pas, c'est au
niveau de l'algorithmique qu'il faut jouer. Mais l'inline vaut
en général le coup d'essai.

--
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 <49c63473$0$17782$,
Merwin wrote:
[au sujet d'inline]
Je voulais une confirmation, pour savoir si je pouvais continuer à les
utiliser pour mes accesseurs ou si c'était une habitude à perdre.



Ca depend de quel point de vue tu te places.

- Cote performance, regarde le code genere, avec ou sans inline.
Si l'accesseur est petit, bien souvent le code inline sera plus petit
que l'appel de fonction lui-meme (surtout si tu prends en compte les
opportunites d'optimisation offertes au code client). Dans ce cas, il n'y
a pas photo: le seul inconvenient d'inline (faire grossir le code) disparait.
Pour des fonctions un peu plus grosses c'est moins clair. Surtout qu'un inline
risque d'ameliorer les choses localement, et que ca n'est pas facile de savoir
ce qui se passe de maniere plus globale: typiquement, si ton code grossit,
a un moment tes boucles ne rentrent plus dans le cache... et ca, ca peut
faire tres mal.

- Cote proprete, tu violes des principes d'encapsulation. En particulier,
tout ce qui est separation physique du code. Si tu modifies ta classe qui
contient les inline, tu es bon pour en recompiler tous les clients. C'est
plus ou moins facile. Mais globalement, faire des choses propres a ce niveau
suppose de bien comprendre ce qui se passe, et de maitriser des idiomes
de "separation" tel que pimpl/compiler firewall. Je ne saurais trop
recommander de jeter un oeil au Lakos (Large scale C++ software development)
a l'occasion...
1 2