OVH Cloud OVH Cloud

Forward déclarer des typedefs

8 réponses
Avatar
Loïc Joly
Bonjour à tous,

Je me trouve souvent avec du code comme ça :
class A {...};
typedef boost::shared_ptr<A> APtr;

Et bien entendu, quand dans un autre fichier, je tente de faire :

class APtr;
class B
{
int f(APtr a);
};

Ca ne marche pas. La question que je me pose, c'est pourquoi ?

Merci,

--
Loïc

8 réponses

Avatar
Franck Branjonneau
Loïc Joly écrivait:

Je me trouve souvent avec du code comme ça :
class A {...};
typedef boost::shared_ptr<A> APtr;

Et bien entendu, quand dans un autre fichier, je tente de faire :

class APtr;
class B
{
int f(APtr a);
};

Ca ne marche pas. La question que je me pose, c'est pourquoi ?


typedef introduit un synonyme : partout où APtr est
utilisé tu peut utiliser boost::shared_ptr<A>, et
réciproquement. Qu'est-ce que cela donne avec :

typedef boost::shared_ptr<A> APtr;
class APtr;

?

typedef boost::shared_ptr<A> APtr;
class boost::shared_ptr<A>;

...
--
Franck Branjonneau

Avatar
Fabien LE LEZ
On Thu, 08 Feb 2007 21:45:44 +0100, Loïc Joly
:

typedef boost::shared_ptr<A> APtr;

Et bien entendu, quand dans un autre fichier, je tente de faire :

class APtr;


"class" introduit un nouveau type.
Or, APtr n'est pas un nouveau type, puisque c'est exactement
"boost::shared_ptr<A>".

Imagine ceci :

class A;
class B;
void f (A const&) {}
void f (B const&) {} // OK, ce n'est pas la même fonction car le
paramètre est différent

typedef A B; // Oups, finalement A et B sont un seul type !

Avatar
James Kanze
Loïc Joly wrote:

Je me trouve souvent avec du code comme ça :
class A {...};
typedef boost::shared_ptr<A> APtr;

Et bien entendu, quand dans un autre fichier, je tente de faire :

class APtr;
class B
{
int f(APtr a);
};

Ca ne marche pas.


Je ne suis pas sûr ce que tu veux dire par : ça ne marche pas.
Si quelque part dans cet autre fichier, tu as inclu le premier,
c'est normal que tu aies un problème. D'une part, tu dis que
APtr est en fait boost::shared_ptr<A>, et de l'autre tu dis que
c'est une classe en soi. Il ne peut pas être les deux.

Si, en revanche, il n'y a pas d'inclusion, il ne doit pas y
avoir de problème. Un nom défini par un typedef n'est pas
visible en dehors de l'unité de compilation où il est déclaré.
Le typedef ne doit pas poser de problème dans la définition
d'une classe du même nom dans une autre unité de compilation.

Enfin, si tu t'attends à ce que la classe APtr dans le deuxième
fichier correspond bien au typedef dans le premier, comme le
semble penser d'autres qui ont répondu, je me démande bien
pourquoi. Tu sais bien que (§3.5/8) « Names not covered by
these rules have no linkage. » Quelle règle donne un linkage au
nom APtr dans le premier fichier ?

Indépendamment des règles, j'aimerais bien savoir comment tu
implémenterais une telle chose. L'implémentation classique des
fonctions décore les noms des fonctions avec des informations
sur les paramètres. Donc, dans le deuxième fichier, on aurait
quelque chose comme __1cBBBf6MnEAPtr__i_ ou _ZN1B1fE4APtr,
tandis qu'avec boost::shared_ptr<A> serait quelque chose comme
__1cBBBf6MnFboostKshared_ptr4nBA____i_ ou
_ZN1B1fEN5boost10shared_ptrI1AEE. D'ailleurs, rien ne t'empèche,
dans le deuxième fichier, d'inclure une définition de la classe
A sans le typedef, et de surcharger f avec un paramètre du type
boost::shared_ptr<A>. C-à-d que la légalité de :

#include <boost/shared_ptr.hpp>
class A ;
class APtr ;

class B
{
int f( APtr ) ;
int f( boost::shared_ptr<A> ) ;
} ;

dépendrait d'un typedef dans une autre unité de compilation, que
le compilateur ne pourrait pas voir (et qui n'est peut-être même
pas écrit au moment que je compile ce code).

--
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
Mathias Gaunard

Je me trouve souvent avec du code comme ça :
class A {...};
typedef boost::shared_ptr<A> APtr;


class APtr : public boost::shared_ptr<A>
{
};

devrait donner plus ou moins ce que tu veux.

Avatar
Falk Tannhäuser
Mathias Gaunard wrote:
class APtr : public boost::shared_ptr<A>
{
};
devrait donner plus ou moins ce que tu veux.


Cette solution t'oblige à redéfinir les constructeurs et opérateurs
d'affectation dans la classe dérivée, ce qui ne me semble pas très
pratique...

Falk

Avatar
Loïc Joly
Loïc Joly wrote:



D'abord, merci à tous ceux qui ont répondu.


Enfin, si tu t'attends à ce que la classe APtr dans le deuxième
fichier correspond bien au typedef dans le premier, comme le
semble penser d'autres qui ont répondu, je me démande bien
pourquoi. Tu sais bien que (§3.5/8) « Names not covered by
these rules have no linkage. » Quelle règle donne un linkage au
nom APtr dans le premier fichier ?


Je savais que ça ne marchais pas (même si je ne savais plus le
paragraphe exact, merci), mais je ne savais pas trop pour quelle raison
on ne l'avait pas fait marcher. Parce que ça pourrait avoir de
l'intérêt. Ainsi, dans mon code, un simple :
class APtr;

Pourrait remplacer les deux alternatives que j'ai actuellement, et qui
m'obligent à trop inclure, et à trop écrire :
#include <shared_ptr.hpp>
class A;
typedef boost::shared_ptr<A> APtr;

ou bien :
#include "A.h"

Aujourd'hui, le type de pointeur intelligent sur A que j'utilise est
spécifié à de multiples points dans mon code, et ça m'ennuie. Ou alors
je peux écrire un fichier "APtr.h" qui ne défini que le typedef, mais ça
me semble lourd d'ajouter un fichier rien que pour ça. A réfléchir.


Indépendamment des règles, j'aimerais bien savoir comment tu
implémenterais une telle chose. L'implémentation classique des
fonctions décore les noms des fonctions avec des informations
sur les paramètres. Donc, dans le deuxième fichier, on aurait
quelque chose comme __1cBBBf6MnEAPtr__i_ ou _ZN1B1fE4APtr,
tandis qu'avec boost::shared_ptr<A> serait quelque chose comme
__1cBBBf6MnFboostKshared_ptr4nBA____i_ ou
_ZN1B1fEN5boost10shared_ptrI1AEE. D'ailleurs, rien ne t'empèche,
dans le deuxième fichier, d'inclure une définition de la classe
A sans le typedef, et de surcharger f avec un paramètre du type
boost::shared_ptr<A>. C-à-d que la légalité de :

#include <boost/shared_ptr.hpp>
class A ;
class APtr ;

class B
{
int f( APtr ) ;
int f( boost::shared_ptr<A> ) ;
} ;

dépendrait d'un typedef dans une autre unité de compilation, que
le compilateur ne pourrait pas voir (et qui n'est peut-être même
pas écrit au moment que je compile ce code).


Ce sont effectivement deux bonnes raisons, et je ne vois guère que
l'introduction d'un typedef fortement typé pour résoudre ces problèmes.

--
Loïc

Avatar
Fabien LE LEZ
On Fri, 09 Feb 2007 21:27:26 +0100, Loïc Joly
:

et je ne vois guère que
l'introduction d'un typedef fortement typé pour résoudre ces problèmes.


Y'a une chance pour que ce graal voie le jour ?

Avatar
Mathias Gaunard

Cette solution t'oblige à redéfinir les constructeurs et opérateurs
d'affectation dans la classe dérivée, ce qui ne me semble pas très
pratique...


Uniquement les constructeurs non défauts, pas de problème avec operator=.
Et le problème des constructeurs sera résolu en permettant l'utilisation
des constructeurs avec using.

À mon avis ils auraient mieux fait de carrément supporter les mixins,
mais bon.