 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Arnaud Debaene Guest
|
Posted: Wed Jul 28, 2004 6:54 pm Post subject: type traits |
|
|
Je suis en train d'implémenter une librairie assez simpliste de type de
traits. La structure de base ressemble à çà :
template <class TType> struct type_traits
{
typedef TType type;
typedef TType* pointer;
typedef TType& ref;
static TType instance(); //not implemented
static const bool isPointer=false;
//autres champs
};
//diverses spécialisations de type_traits pour TType*, TType&, etc...
Maintenant, j'essaie d'implémenter des fonctionnalité pour comparer les
types entre eux (fortement inspiré de Loki). Par exemple :
template <class Base, class Derived> struct IsBaseAndDerived
{
private:
struct big {char mem[2];};
struct IsBaseAndDerivedHelper
{
static big TestFct(typename type_traits<Base>::pointer);
static char TestFct(...);
};
public:
static const bool value =
(sizeof(reinterpret_cast<typename type_traits(0))
//1
== sizeof(char));
};
template <class Base> struct IsBaseAndDerived <Base, Base>
{
static const bool value = true;
};
template <class Derived> struct IsBaseAndDerived <void, Derived>
{
static const bool value=false;
};
J'ai des problèmes d'utilisation dans certains cas :
struct VirtualClass
{
virtual void f() =0;
};
struct S {};
bool is_derived=IsBaseAndDerived<C, VirtualClass>::value; //*
g++ 3.1 accepte de compiler la ligne //*, mais VC7.1 et Comeau online
refusent car, lors de l'instantiation, ils se plaignent que VirtualClass est
virtuelle et qu'ils ne peuvent donc pas implémenter type_traits::instance().
Qui a raison? Et si le code est effectivement faux, comment le corriger
(dans la mesure du possible, j'aimerais conserver instance() dans
type_traits).
Arnaud
|
|
| Back to top |
|
 |
Fabien LE LEZ Guest
|
Posted: Thu Jul 29, 2004 9:03 am Post subject: Re: type traits |
|
|
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
<adebaene (AT) club-internet (DOT) fr>:
| Quote: | template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits(0))
|
Euh... pour les histoires de dérivation, c'est pas plutôt
dynamic_cast<> qu'il faut tester ?
--
;-)
|
|
| Back to top |
|
 |
drkm Guest
|
Posted: Thu Jul 29, 2004 12:29 pm Post subject: Re: type traits |
|
|
Fabien LE LEZ <gramster (AT) gramster (DOT) com> writes:
| Quote: | On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
[email]adebaene (AT) club-internet (DOT) fr[/email]>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits(0))
Euh... pour les histoires de dérivation, c'est pas plutôt
dynamic_cast<> qu'il faut tester ?
|
Je dirais tout simplement un static_cast<>. Il ne peut utiliser de
dynamic_cast, puisque l'on se trouve à la compilation. Il surcharge
donc une fonction, l'une prenant un pointeur sur Base, et l'autre un
nombre d'argument variable. Les deux renvoient des types de donnée de
tailles différentes. Tout cela est bien connu à la compilation. On
teste alors la taille du retour d'un appel de la fonction avec un
simple pointeur null. Le cast sert à donner le type du pointeur null.
Si je me souviens bien, les arguments variables sont nécessaire pour
accepter n'importe quel type d'argument, sans fournir de meilleur
match pour Derived, comme le ferait un modèle de fonction membre.
--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html
|
|
| Back to top |
|
 |
Arnaud Debaene Guest
|
Posted: Thu Jul 29, 2004 4:00 pm Post subject: Re: type traits |
|
|
Fabien LE LEZ <gramster (AT) gramster (DOT) com> wrote
| Quote: | On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
[email]adebaene (AT) club-internet (DOT) fr[/email]>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits(0))
Euh... pour les histoires de dérivation, c'est pas plutôt
dynamic_cast<> qu'il faut tester ?
|
Non, le but là c'est de créer un pointeur vers le type dérivé
(Derived* dans le cas général, autre chose si Derived correspond à des
spécialisations de type_traits).
De toute façon, le tout est dans un sizeof, donc ce code n'est jamais
executé, il ne génère même pas de code compilé! C'est juste un test à
la compilation!
Arnaud
|
|
| Back to top |
|
 |
Falk Tannhäuser Guest
|
Posted: Fri Jul 30, 2004 9:08 am Post subject: Re: type traits |
|
|
Fabien LE LEZ wrote:
| Quote: |
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
[email]adebaene (AT) club-internet (DOT) fr[/email]>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits(0))
|
Pourquoi pas "sizeof(typename type_traits<Derived>::pointer)" tout simplement ?
Falk
|
|
| Back to top |
|
 |
drkm Guest
|
Posted: Fri Jul 30, 2004 11:31 am Post subject: Re: type traits |
|
|
Falk Tannhäuser <falk.tannhauser (AT) crf (DOT) canon.fr> writes:
| Quote: | Fabien LE LEZ wrote:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
[email]adebaene (AT) club-internet (DOT) fr[/email]>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits(0))
Pourquoi pas "sizeof(typename type_traits<Derived>::pointer)" tout
simplement ?
|
Parce qu'il s'agit en fait, je pense, de :
typedef typename type_traits< Derived >::pointer Pointer ;
... = sizeof( TestFct( static_cast< Pointer >( 0 ) ) ) ;
J'ai changé le reinterpret_cast<> en static_cast<> ; je pense que ça
ne change rien au comportement, mais c'est la manière idiomatique
d'obtenir un pointeur null typé selon nos besoins. Mais surtout, je
pense qu'il manquait l'appel à TestFct(). Correct ?
--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html
|
|
| Back to top |
|
 |
Arnaud Debaene Guest
|
Posted: Fri Jul 30, 2004 2:34 pm Post subject: Re: type traits |
|
|
Falk Tannhäuser <falk.tannhauser (AT) crf (DOT) canon.fr> wrote
| Quote: | Fabien LE LEZ wrote:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
[email]adebaene (AT) club-internet (DOT) fr[/email]>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits(0))
Pourquoi pas "sizeof(typename type_traits<Derived>::pointer)" tout simplement ?
|
Parce que j'ai écrit n'importe quoi dans mon premier post Je
reprnds donc :
template <class TType> struct type_traits
{
typedef TType type;
typedef TType* pointer;
typedef TType& ref;
static TType instance(); //not implemented
static const bool isPointer=false;
//autres champs
};
//diverses spécialisations de type_traits pour TType*, TType&, etc...
template <class Base, class Derived> struct IsBaseAndDerived
{
private:
struct big {char mem[2];};
struct IsBaseAndDerivedHelper
{
static big TestFct(typename type_traits<Base>::pointer);
static char TestFct(...);
};
public:
static const bool value =
(sizeof(IsBaseAndDerivedHelper::TestFct(reinterpret_cast<typename
type_traits(0))) == sizeof(big));
};
template <class Base> struct IsBaseAndDerived <Base, Base>
{
static const bool value = true;
};
template <class Derived> struct IsBaseAndDerived <void, Derived>
{
static const bool value=false;
};
Et le cas d'utilisation qui pose problème est :
struct VirtualClass
{
virtual void f() =0;
};
struct S {};
bool is_derived=IsBaseAndDerived<S, VirtualClass>::value;
Effectivement, on pourrait remplacer le reinterpret_cast par un
static_cast, mais je tenais à mettre en exergue que ce n'est pas une
manipulation normale de pointeur, mais juste un "truc" pour comparer 2
types.
Pour revenir à ma question intiale : Il semblerait que GCC a tort
d'accepter ce code car lorsque l'on écrit
type_traits<Derived>::pointer, il faut garantir que toute la
déclaration de type_traits<Derived> est valide. Dans mon cas, c'est
impossible car il est illégal pour une méthode de retourner par valeur
une classe abstraite.
Arnaud
|
|
| Back to top |
|
 |
drkm Guest
|
Posted: Fri Jul 30, 2004 3:34 pm Post subject: Re: type traits |
|
|
[email]adebaene (AT) club-internet (DOT) fr[/email] (Arnaud Debaene) writes:
| Quote: | Effectivement, on pourrait remplacer le reinterpret_cast par un
static_cast, mais je tenais à mettre en exergue que ce n'est pas une
manipulation normale de pointeur, mais juste un "truc" pour comparer 2
types.
|
Je pense au contraire que le « truc » consiste à comparer les
tailles d'un type sentinelle et du type de retour d'une fonction. Le
cast n'est là que pour donner un type précis au pointeur null.
L'utilisation idiomatique est alors static_cast<>, il me semble.
Lorsque j'ai vu reinterpret_cast<>, je me suis arrêté, et me suis
demandé pourquoi tu avais utilisé un tel cast, comme d'habitude
lorsque je rencontre un reinterpret_cast<>. Je pense que cela fait se
poser des questions inutiles au lecteur de ton code. Avec un
static_cast<>, il se concentre plutôt sur le « truc » de la
comparaison des tailles.
AMHA.
--drkm, en recherche d'un stage : http://www.fgeorges.org/ipl/stage.html
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|