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];};
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).
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(0))
Euh... pour les histoires de dérivation, c'est pas plutôt dynamic_cast<> qu'il faut tester ?
-- ;-)
drkm
Fabien LE LEZ writes:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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
Fabien LE LEZ <gramster@gramster.com> writes:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
<adebaene@club-internet.fr>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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
adebaene
Fabien LE LEZ wrote in message news:...
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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
Fabien LE LEZ <gramster@gramster.com> wrote in message news:<p8fhg0dlcjheqo4g53v0at2g7bi9f7nh73@4ax.com>...
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
<adebaene@club-internet.fr>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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!
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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
Falk Tannhäuser
Fabien LE LEZ wrote:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(0))
Pourquoi pas "sizeof(typename type_traits<Derived>::pointer)" tout simplement ?
Falk
Fabien LE LEZ wrote:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
<adebaene@club-internet.fr>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(0))
Pourquoi pas "sizeof(typename type_traits<Derived>::pointer)" tout simplement ?
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
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
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
adebaene
Falk Tannhäuser wrote in message news:...
Fabien LE LEZ wrote:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene" :
template <class Base, class Derived> struct IsBaseAndDerived ... (sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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 :
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
Falk Tannhäuser <falk.tannhauser@crf.canon.fr> wrote in message news:<410A0FF5.11584C43@crf.canon.fr>...
Fabien LE LEZ wrote:
On Wed, 28 Jul 2004 20:54:26 +0200, "Arnaud Debaene"
<adebaene@club-internet.fr>:
template <class Base, class Derived> struct IsBaseAndDerived
...
(sizeof(reinterpret_cast<typename type_traits<Derived>::pointer>(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 :
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.
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
drkm
(Arnaud Debaene) writes:
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
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
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