OVH Cloud OVH Cloud

Comment déclarer friend un paramètre template d'une classe ?

16 réponses
Avatar
Helfer Thomas
Cette question est liée à l'impossibilité d'écrire le code suivant :

template<class T>
struct Test
{
friend class T;
};

Existerait-il un moyen (détourné) de faire cela ?

Cordialement,

Helfer Thomas

10 réponses

1 2
Avatar
Sylvain
Helfer Thomas wrote on 18/07/2006 23:23:
Cette question est liée à l'impossibilité d'écrire le code suivant :

template<class T>
struct Test
{
friend class T;
};

Existerait-il un moyen (détourné) de faire cela ?


je suppose que le /struct/ Test vient du fait qu'en effet avec une
/classe/ template cela ne passe pas (parce que écrit comme cela ça passe
évidemment).

si c'est du cas par cas, vous pouvez forcez la génération du code
template et résoudre l'impossibilité par:

lib:

template<class T>
class Test
{
...
};

code applicatif:

class theT;

class TestTheT : public Test<TheT> {
friend class TheT;
};

Sylvain.

Avatar
Helfer Thomas
Le Wed, 19 Jul 2006 00:44:02 +0200, Sylvain a écrit :

Helfer Thomas wrote on 18/07/2006 23:23:
Cette question est liée à l'impossibilité d'écrire le code suivant :

template<class T>
struct Test
{
friend class T;
};

Existerait-il un moyen (détourné) de faire cela ?


je suppose que le /struct/ Test vient du fait qu'en effet avec une
/classe/ template cela ne passe pas (parce que écrit comme cela ça passe
évidemment).

Non le problème est le même que l'on soit en struct ou en class. De

manière plus précise, le morceau de code écrit plus haut conduit au
message d'erreur suivant (gcc-4.0) :

essai.cxx:15: erreur: using template type parameter «T» after «class»
essai.cxx:15: erreur: déclaration amie ne nomme pas une classe ou une
fonction

Votre proposition est intéressante, mais n'a pas la souplesse du code que
je souhaiterai écrire.

Cordialement,

Helfer Thomas


Avatar
Helfer Thomas
Le Tue, 18 Jul 2006 23:23:59 +0200, Helfer Thomas a écrit :

Voici un extrait de la faq du compilateur Comeau qui explique
plus en détails mon soucis :

What's wrong with saying friend class T within a template?
Trying to use a template parameter in a friend is ill-formed:

template <typename T>
class xyz {
friend class T; // ill-formed code
};

According to Section 7.1.5.3 paragraph 2 of Standard C++:

3.4.4 describes how name lookup proceeds for the identifier
in an elaborated-type-specifier. ... If the identifier
resolves to a typedef-name or a template type-parameter,
the elaborated-type-specifier is ill-formed.
[Note: this implies that, within a class template
with a template type-parameter T, the declaration
friend class T;
is ill-formed. ]

The next thing one would try would be:

template <typename T>
class xyz {
friend T;
};

but this form is not allowed either because for friends, according
to 11.4 paragraph 2

An elaborated-type-specifier shall be used in a friend
declaration for a class.

And also from footnote #101:

The class-key of the elaborated-type-specifier is required.

You could also probably try some hackery with typedef, but I
suspect all of these attempts will also be illegal.

Le code que j'aimerai utilisé est donc illegal en C++ standard, d'où la
recherche d'une solution détournée...

Merci pour votre aide

Cordialement,

Helfer Thomas



Cette question est liée à l'impossibilité d'écrire le code suivant :

template<class T>
struct Test
{
friend class T;
};

Existerait-il un moyen (détourné) de faire cela ?

Cordialement,

Helfer Thomas


Avatar
kanze
Sylvain wrote:
Helfer Thomas wrote on 18/07/2006 23:23:
Cette question est liée à l'impossibilité d'écrire le code suiv ant :

template<class T>
struct Test
{
friend class T;
};

Existerait-il un moyen (détourné) de faire cela ?


je suppose que le /struct/ Test vient du fait qu'en effet avec
une /classe/ template cela ne passe pas (parce que écrit comme
cela ça passe évidemment).


Tu pourrais t'expliquer. Parce que je ne vois pas la moindre
différence entre struct et class ici.

Le code est illégal, c'est sûr. (Je ne serais pas étonné qu'il y
ait une proposition pour résoudre le problème dans la prochaine
version de la norme. Mais ça n'aide pas dans l'immédiat.)

A priori, je ne connais pas de bon work-around, à part rendre
tous les membres de Test public (ce qui permettrait, évidemment,
à classe T d'y accéder, mais aussi à toutes les autres classes).
La plus proche que je peux penser, c'est d'écrire une deuxième
classe template, TestAccessor, de le déclarer comme ami de Test,
et lui pourvoir avec les fonctions (protegées) qui effectuent
tous les accès nécessaire. Aussi, on ne lui donne que un
constructeur protégé, et on utilise des contraints pour assurer
que T dérive de lui. (Est-ce qu'on pourrait s'assurer d'une
façon statique qu'aucune autre classe dérive de lui ?) Quelque
chose du genre :

template< typename T >
class TestAccessor ;

template< typename T >
class Test
{
friend class TestAccessor< T > ;

int i ;
// ...
} ;

template< typename T >
class TestAccessor : boost::noncopiable
{
protected:
int& testI( Test< T >* p ) {
assert( dynamic_cast< T* >( this ) != NULL ) ;
return p->i ;
}
// ...

TestAccessor()
{
T* p = static_cast< T* >( this ) ;
}
} ;

Ça exige que T dérive de TestAccessor<T>, et est contournable,
mais ça doit éviter les accès accidentaux.

--
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
Arnaud Meurgues
Gabriel Dos Reis wrote:

Merci d'avoir insisté...

template<class T>
struct Test
{
friend T;
};

Note l'absence de « class. »


Pourquoi pas class ?
Parce que aucun autre identifieur ne serait valable qu'une fonction qui
serait reconnaissable ?
Ou bien parce que le
template <class T>
a déjà précisé que T était une classe ?
Ou pour une autre raison sioux qui m'échappe ?

--
Arnaud

Avatar
Arnaud Meurgues
Gabriel Dos Reis wrote:

Parce que le « class » dans « friend class T » dit vraiment que T est
une classe (i.e. quelque déclarée avec « class » ou « struct. »)
[...]

le « class » dans « template<class T> » est la même chose que
« typename », ce qui est différent.


Parfois, je me demande pourquoi j'aime le C++... ;-)

--
Arnaud

Avatar
Fabien LE LEZ
On Wed, 19 Jul 2006 17:29:57 +0200, Arnaud Meurgues
:

Parfois, je me demande pourquoi j'aime le C++... ;-)


N'est-ce pas Winston Churchill qui a dit "Le C++ est le pire des
langages, à l'exception de tous les autres" ?

Avatar
Gabriel Dos Reis
"kanze" writes:

| Sylvain wrote:
| > Helfer Thomas wrote on 18/07/2006 23:23:
| > > Cette question est liée à l'impossibilité d'écrire le code suivant :
|
| > > template<class T>
| > > struct Test
| > > {
| > > friend class T;
| > > };
|
| > > Existerait-il un moyen (détourné) de faire cela ?
|
| > je suppose que le /struct/ Test vient du fait qu'en effet avec
| > une /classe/ template cela ne passe pas (parce que écrit comme
| > cela ça passe évidemment).
|
| Tu pourrais t'expliquer. Parce que je ne vois pas la moindre
| différence entre struct et class ici.
|
| Le code est illégal, c'est sûr. (Je ne serais pas étonné qu'il y
| ait une proposition pour résoudre le problème dans la prochaine
| version de la norme. Mais ça n'aide pas dans l'immédiat.)

En effet. À chaque fois que j'avais soulevé le problème, j'ai toujours
des explications techniques obscures liées à l'histoire. Finalement, à
force d'insister, le langage a été changé. Mike Miller a gentiment
pris le bébé et a proposé une modification qui a été acceptée dans le
brouillon actuel -- il y a deux ou trois réunions je crois.
Maintenant il est possible de dire

template<class T>
struct Test
{
friend T;
};

Note l'absence de « class. »

-- Gaby
Avatar
Laurent Deniau
Gabriel Dos Reis wrote:
Arnaud Meurgues writes:

| Gabriel Dos Reis wrote:
|
| > Parce que le « class » dans « friend class T » dit vraiment que T est
| > une classe (i.e. quelque déclarée avec « class » ou « struct. »)
| [...]
| > le « class » dans « template<class T> » est la même chose que
| > « typename », ce qui est différent.
|
| Parfois, je me demande pourquoi j'aime le C++... ;-)

http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2003/n1520.pdf
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1616.pdf
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1722.pdf
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1791.pdf


vous avez pas les memes au format patch ou un cvs qqpart? ;-)

a+, ld.

Avatar
Gabriel Dos Reis
Arnaud Meurgues writes:

| Gabriel Dos Reis wrote:
|
| Merci d'avoir insisté...
|
| > template<class T>
| > struct Test
| > {
| > friend T;
| > };
| >
| > Note l'absence de « class. »
|
| Pourquoi pas class ?

Parce que le « class » dans « friend class T » dit vraiment que T est
une classe (i.e. quelque déclarée avec « class » ou « struct. ») Que
se passe-t-il avec

union foo { /* ... */ };

Test<foo> x;

?

| Parce que aucun autre identifieur ne serait valable qu'une fonction qui
| serait reconnaissable ?
| Ou bien parce que le
| template <class T>
| a déjà précisé que T était une classe ?

le « class » dans « template<class T> » est la même chose que
« typename », ce qui est différent.

-- Gaby
1 2