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

template friend operator

18 réponses
Avatar
meow
Bonjour,

=E7a a l'air d'etre un probl=E8me archi connu et rabach=E9, mais je n'ai
pas trouv=E9 la r=E9ponse ni sur la toile ni sur cette mailing
(probablement les mauvais mots clefs).

template <class T>
class A {
friend A<T> operator +<>(A<T>,A<T>);
};

template <class T>
A<T> operator+ (A<T>,A<T>){
}

error: template-id 'operator+<>' does not match any template
declaration

si je retire les vilains <> dans la d=E9claration friend operator :
warning: friend declaration declares a non-template function

(gcc 4.0.3 sous debian)

10 réponses

1 2
Avatar
Fabien LE LEZ
On Fri, 23 Nov 2007 08:42:09 -0800 (PST), meow
:

template <class T>
class A {
friend A<T> operator +<>(A<T>,A<T>);
};


La méthode canonique serait plutôt :

class C
{
public:
C& operator+= (C const&);
};

C operator + (C const& a, C const& b)
{
C a;
a+= b;
return a;
}

Avatar
Serge Paccalin
Le samedi 24 novembre 2007 à 01:03:16, Fabien LE LEZ a écrit dans
fr.comp.lang.c++ :

On Fri, 23 Nov 2007 08:42:09 -0800 (PST), meow
:

template <class T>
class A {
friend A<T> operator +<>(A<T>,A<T>);
};


La méthode canonique serait plutôt :

class C
{
public:
C& operator+= (C const&);
};

C operator + (C const& a, C const& b)
{
C a;
a+= b;
return a;
}


C tmp(a);
tmp += b;
return tmp;


--
___________
_/ _ _`_`_`_) Serge PACCALIN -- sp ad mailclub.net
_L_) Il faut donc que les hommes commencent
-'(__) par n'être pas fanatiques pour mériter
_/___(_) la tolérance. -- Voltaire, 1763


Avatar
Fabien LE LEZ
On Sat, 24 Nov 2007 10:17:18 +0100, Serge Paccalin :

C tmp(a);
tmp += b;
return tmp;


Gloups, oui, effectivement. Désolé.

Avatar
James Kanze
On Nov 23, 5:42 pm, meow wrote:

ça a l'air d'etre un problème archi connu et rabaché, mais je n'a i
pas trouvé la réponse ni sur la toile ni sur cette mailing
(probablement les mauvais mots clefs).

template <class T>
class A {
friend A<T> operator +<>(A<T>,A<T>);
};


Attention : ici, tu n'as pas déclaré une template comme ami,
mais une fonction non-template. Selon la norme, je crois ce que
tu veux, c'est :

friend A<T> operator+< A< T > >( A< T >, A< T > ) ;

Seulement, dans ce cas-là, il faudrait une declaration du
template de la fonction avant la classe. Quelque chose du
genre :

template< typename T > class A ;
template< typename T > A< T > operator+( A< T >, A< T > ) ;

template< typename T >
class A {
friend A< T > operator+< A< T > >( A< T >, A< T > ) ;
// ...
} ;

Enfin, c'est comme ça que je comprends la norme. Je ne l'ai
jamais essayé dans la pratique. Pour le cas des operator
arithmetiques binaires, par exemple, je fais quelque chose du
genre :

template< typename T >
class A : public ArithmeticOperators< A< T > >
{
public
A& operator+=( A const& other ) ;
// ...
} ;

Le template de classe ArithmeticOperators s'occupe de générer un
operator+ (en tant que fonction libre) à partir de l'operator+=.

Plus généralement, dans les templates de classe, j'implémente
toutes les fonctionnalités par des fonctions membres, puis je me
sers de l'idiome de Barton et Nackman pour en générer des
fonctions libres, si j'en ai besoin. Si, par exemple, pour une
raison ou une autre (peut-être des questions de performance), je
ne voulais pas implémenter operator+ au moyen de l'operator+=,
je ferais quelque chose du genre :

template< typename T >
class A
{
public:
A add( A const& other ) const ;
friend A operator+( A const& lhs, A const& rhs )
{
return lhs.add( rhs ) ;
}
} ;

(Du coup, l'operator + n'est pas un template ! Mais chaque
instantiation du template de classe A génèrerait une declaration
d'une nouvelle fonction libre. Et une définition, si jamais la
fonction est réelement appelée.)

template <class T>
A<T> operator+ (A<T>,A<T>){
}

error: template-id 'operator+<>' does not match any template
declaration

si je retire les vilains <> dans la déclaration friend operator :
warning: friend declaration declares a non-template function


Est-ce que tu aurais un exemple du cas où tu as
l'avertissement ? Je m'y attendrais éventuellement pour ce que
tu as écrit ci-dessus.

--
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
meow
Bonjour, et merci pour vos réponses. Avant de continuer, je tiens à
préciser que mes soucis sont inhérents à la reprise d'un vieux code
(bibliothèque de minimisation coool). Pour info, le fichier dans
lequel j'ai expérimenté les soucis exposés ici date de 1994 Si ça pe ut
aider...

@Fabien, c'est essentiellement l'emploi du template qui complique
tout ;)

@Kanze:

Attention : ici, tu n'as pas déclaré une template comme ami,
mais une fonction non-template.


Euh, je t'avoues que je ne connais déjà pas cette notation avec les
chevrons vides :/
J'ai découvert récemment qu'on pouvait utiliser ce genre d'écriture
pour définir une implémentation particulière d'une fonction ou d'une
classe déclarée template et dont on souhaite instancier les arguments
template...

Selon la norme, je crois ce que tu veux, c'est :
friend A<T> operator+< A< T > >( A< T >, A< T > ) ;


J'ai essayé (dans mon cas A = Model et T=Type ), et gcc n'est toujours
pas content :
(Dans mon exemple j'ai
../../include/coool/Model.hh:226: error: template-id 'operator
+<Model<double> >' for 'Model<double> operator+(const Model<double>&,
const std::valarray<double>&)' does not match any template declaration

Cela étant, je ne comprends pas ton écriture, et de plus je ne vois
pas ce que cela donnerait pour les cas où j'ai des arguments d'autres
types que Model<Type>:
friend Model<Type> operator+<>(const Model<Type>&, const
Model<Type>&);
friend Model<Type> operator+<>(const Model<Type>&, const
std::valarray<Type>&);
friend Model<Type> operator+<>(const std::valarray<Type>&,
const Model<Type>&);
friend Model<Type> operator*<>(Type, const Model<Type>&);

Et puis il ne faudrait pas spécifier explicitement qu'on a qu'il
s'agit d'une fonction template, un truc du genre :
template<>
friend Model<Type> operator+<Type>(const Model<Type>&, const
std::valarray<Type>&);
(j'ai l'impression d'etre un singe savant... Avec un peu de chance je
réécrirai proust avant d'avoir réussi à faire compiler/fonctionner m a
bibliothèque)

Seulement, dans ce cas-là, il faudrait une declaration du
template de la fonction avant la classe. Quelque chose du
genre :


En effet, c'est d'ailleurs le cas dans le fichier en question.
D'ailleurs, j'ai copié collé des sous parties un peu plus bas dans ce
message comme tu me l'avais demandé.

Pour le cas des operator
arithmetiques binaires, par exemple, je fais quelque chose du
genre :
Le template de classe ArithmeticOperators s'occupe de générer un
operator+ (en tant que fonction libre) à partir de l'operator+=.


Tu veux dire que si dans mon cas je commentes les déclarations et
définitions des fonctions libres, le compilo sera assez aimable pour
m'en fournir automatiquement a partir des operateurs operation= (+=,
*=, ...) de classe ?

Plus généralement, dans les templates de classe, j'implémente
toutes les fonctionnalités par des fonctions membres, puis je me
sers de l'idiome de Barton et Nackman pour en générer des
fonctions libres, si j'en ai besoin. Si, par exemple, pour une
raison ou une autre (peut-être des questions de performance), je
ne voulais pas implémenter operator+ au moyen de l'operator+=,
je ferais quelque chose du genre :

template< typename T >
class A
{
public:
A add( A const& other ) const ;
friend A operator+( A const& lhs, A const& rhs )
{
return lhs.add( rhs ) ;
}
} ;


Hum, ça me semble séduisant... Donc, remonter les définitions des
fonctions libres dans la classe, et supprimer les déclarations
templates... Après tout, oui, il n'y a pas de raison que j'utilise cet
operateur libre sur des types que je n'aurai pas défini... ça peut
fonctionner.

Est-ce que tu aurais un exemple du cas où tu as
l'avertissement ? Je m'y attendrais éventuellement pour ce que
tu as écrit ci-dessus.


ci dessous :

----------------------

//Model.hh
template <class Type>
class Model;
...
template <class Type>
Model<Type> operator+(const Model<Type>&, const Model<Type>&);
...
template <class Type>
class Model {
...
friend Model<Type> operator+<>(const Model<Type>&, const
Model<Type>&);
...
};
...
template<typename Type>
Model<Type> operator+(const Model<Type>& m, const Model<Type>& m1){
Model<Type> m2(m);
m2 += m1;
return m2;
}
...

gcc dit
../../include/coool/Model.hh:226: error: template-id 'operator+<>' for
'Model<double> operator+(const Model<double>&, const
std::valarray<double>&)' does not match any template declaration

Et la ligne 426 c'est la déclaration friend dans la définition de la
classe

----------------------
Et si je comprends bien ta question tu veux aussi savoir ce qui lève
le soucis
../../include/coool/Model.hh: In instantiation of 'Model<double>':
templates.cc:10: instantiated from here
09 #include "coool/Model.hh"
10 template class Model<double>;

En tous les cas, merci pour le temps et la patience.

Avatar
Fabien LE LEZ
On Mon, 26 Nov 2007 02:09:35 -0800 (PST), meow
:

@Fabien, c'est essentiellement l'emploi du template qui complique
tout


Il m'avait semblé que le problème venait du mélange de "friend" et de
templates. C'est pourquoi je t'indiquais que dans le cas que tu
présentes, on n'utilise généralement pas friend, ce qui devrait
résoudre ton problème.

Avatar
meow
Il m'avait semblé que le problème venait du mélange de "friend" et d e
templates. C'est pourquoi je t'indiquais que dans le cas que tu
présentes, on n'utilise généralement pas friend, ce qui devrait
résoudre ton problème.


OK, je ne l'avais pas compris :)

Donc ce que tu préconnisais, c'est de supprimer le friend dans la
mesure où on emploie de toute façon des méthodes publiques (les
opérateurs définis dans la classe) de la classe pour coder les
opérateurs libres. En effet, ça devrait fonctionner (et du coups je me
demande meme pourquoi ces fonctions sont déclarées amies), sauf pour
certains comme ==, !=, << où des champs privés sont accédés :/=

Avatar
meow
Oh, tant que j'y suis, je me rends compte qu'il y a deux petites
choses évoquées dans ce thread qui ne sont pas claires pour moi et que
je n'avais pas remarquées précédemment.

Dans le post de Kanze :

template< typename T >
class A : public ArithmeticOperators< A< T > >
{
public
A& operator+=( A const& other ) ;
// ...
} ;


tu voulais dire A<T>& operator +=(A<T> const& other) ? Ou bien ton
ecriture est elle aussi valide ?

Et dans mon post, je me rends compte que je ne comprends pas le
fichier template.cc qui lève l'erreur :

#include "coool/Model.hh"
template class Model<double>;

C'est quoi cette utilisation du mot clef template ? Et concrètement,
qu'est-ce qu'on fait là ? a cette ligne ? Une tentative de deviner :
on déclare l'existence d'une classe Model<double>, et on force ce
faisant l'instantiation du template par le compilo ?

Ou plus loin

template double std::min(const DiagMatrix<double>&m);
la présence du std me trouble... j'ai bien trouvé une fonction libre
min avec une signature compatible dans le fichier DiagMatrix.cc, mais
point de std... Je suis dubitatif.

Avatar
Fabien LE LEZ
On Mon, 26 Nov 2007 05:34:43 -0800 (PST), meow :

(et du coups je me
demande meme pourquoi ces fonctions sont déclarées amies), sauf pour
certains comme ==, !=, << où des champs privés sont accédés :/


Pour == et !=, as-tu une raison particulière pour préférer une
fonction non-membre amie à une fonction membre ?

class A
{
public:
bool operator == (A const&) const;
};

Pour <<, généralement, on passe par une fonction membre
Print(ostream&). Toutefois, commence par te demander si tu as
réellement besoin d'accéder à des membres privés. En effet, << a pour
rôle d'afficher à l'écran (ou autre ostream) l'état observable de
l'objet ; logiquement, toutes les données qu'il affiche devrait être
accessibles (au moins en lecture) par du code extérieur (i.e. via
l'interface publique).

Avatar
Fabien LE LEZ
On Mon, 26 Nov 2007 06:27:34 -0800 (PST), meow
:

Dans le post de Kanze :


Pourquoi n'y réponds-tu pas directement, au lieu de poster en réponse
à ton propre message ?

1 2