 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Frédéric Gourul Guest
|
Posted: Thu Jan 15, 2004 1:18 pm Post subject: cast & pointeurs de fonction... |
|
|
Bonjour,
Après quelques expérimentations avec les pointeurs de fonction, j'ai
désormais une question précise sur le sujet.
Considérons les classes suivantes:
class CTest
{
public:
virtual void foo() {cout << "call CTest::foo" << endl;}
virtual int foo2() {cout << "call CTest::foo2" << endl; return 0;}
virtual CTest* foo3() {cout << "call CTest::foo3" << endl; return this;}
};
class CTestD : public CTest
{
public:
virtual CTestD* foo3() {cout << "call CTestD::foo3" << endl; return this;}
};
et que je déclare les pointeurs de fonction suivant:
CTest c; CTestD d;
void(CTest::*pf)() = &CTest::foo;
CTest*(CTest::*pf2)() = &CTest::foo3;
j'aimerai pouvoir transmettre à pf des fonctions ayant une valeur de retour
de n'importe quel type puisque je ne l'exploite pas au travers de mon
pointeur. Et j'aimerai pouvoir transmettre à pf2 des fonctions dont le type
de retour pourraient être des pointeurs sur des classes dérivée de CTest*
si je n'ai pas vraiment de scrupules à écrire:
pf = reinterpret_cast
un reinterpret_cast... pas taper!!!
je ne veux pas écrire:
CTest*(CTestD::*pf3)() =
reinterpret_cast<CTest*(CTestD::*)()>(&CTestD::foo3);
ce qui reviendrait dans ce cas à autoriser tout et n'importe quoi, ce que je
ne veux pas évidemment...
Bien entendu, tout cela est encapsulé dans une classe template dont le type
générique est le type de la valeur retournée par le pointeur de fonction.
Quelqu'un a-t-il un idée pour n'autoriser que la conversion T -> void et les
conversions légales autorisées par static_cast<> ?
Merci pour votre aide, toujours la bienvenue :)
|
|
| Back to top |
|
 |
Frédéric Gourul Guest
|
Posted: Thu Jan 15, 2004 3:23 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
"Yannick Le goc" <legoc (AT) imag (DOT) fr> a écrit dans le message news:
bu6954$jpl$1 (AT) trompette (DOT) imag.fr...
| Quote: | Tout d'abord, helas dans le standard, il n'y a pas de conversion
implicite d'un type pointeur de fonction vers un autre. Tu n'echapperas
a priori pas au reinterpret_cast.
C'est pas grave, tu peux toujours effectuer un controle de type
dynamique ou statique par les template qui sera cache a l'utilisateur.
|
J'aimerai bien en effet faire contrôler les types au compilateur, car je
veux qu'une conversion "non autorisée" soit rejetée par le compilateur. Je
n'ai aucune idée de la manière dont on peut faire ca...
| Quote: | On y verrait un peu plus clair si tu donnais le squelette de ta classe
template qui encapsule le tout?
|
La voilà:
template <class C, typename R>
class PTest
{
private:
C* c;
R(C::*pf)();
public:
PTest(C* c, R(C::*m)()) :c(c), pf(m) {}
template <typename T>
PTest(C* c, T(C::*m)()) :c(c)
{
// contrôles de conversion: T -> R
pf = reinterpret_cast<R(C::*)()>(m);
}
virtual R operator()() {return (c->*pf)();}
};
Et voici de quoi tester. Actuellement, tout est permis par le compilo :(
CTest c;
CTestD d;
PTest<CTest, void> pt0(&c, &CTest::foo); // valide
PTest<CTest, int> pt1(&c, &CTest::foo); // invalide
PTest<CTest, int> pt2(&c, &CTest::foo2); // valide
PTest<CTest, void> pt3(&c, &CTest::foo2); // valide
PTest<CTestD, CTestD*> pt4(&d, &CTestD::foo3); // valide
PTest<CTestD, CTest*> pt5(&d, &CTestD::foo3); // valide
PTest<CTest, CTestD*> pt6(&c, &CTest::foo3); // invalide
Merci pour ton aide:
|
|
| Back to top |
|
 |
Yannick Le goc Guest
|
Posted: Thu Jan 15, 2004 3:46 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
Frédéric Gourul wrote:
| Quote: | Bonjour,
Après quelques expérimentations avec les pointeurs de fonction, j'ai
désormais une question précise sur le sujet.
Considérons les classes suivantes:
class CTest
{
public:
virtual void foo() {cout << "call CTest::foo" << endl;}
virtual int foo2() {cout << "call CTest::foo2" << endl; return 0;}
virtual CTest* foo3() {cout << "call CTest::foo3" << endl; return this;}
};
class CTestD : public CTest
{
public:
virtual CTestD* foo3() {cout << "call CTestD::foo3" << endl; return this;}
};
et que je déclare les pointeurs de fonction suivant:
CTest c; CTestD d;
void(CTest::*pf)() = &CTest::foo;
CTest*(CTest::*pf2)() = &CTest::foo3;
j'aimerai pouvoir transmettre à pf des fonctions ayant une valeur de retour
de n'importe quel type puisque je ne l'exploite pas au travers de mon
pointeur. Et j'aimerai pouvoir transmettre à pf2 des fonctions dont le type
de retour pourraient être des pointeurs sur des classes dérivée de CTest*
si je n'ai pas vraiment de scrupules à écrire:
pf = reinterpret_cast
un reinterpret_cast... pas taper!!!
je ne veux pas écrire:
CTest*(CTestD::*pf3)() =
reinterpret_cast<CTest*(CTestD::*)()>(&CTestD::foo3);
ce qui reviendrait dans ce cas à autoriser tout et n'importe quoi, ce que je
ne veux pas évidemment...
Bien entendu, tout cela est encapsulé dans une classe template dont le type
générique est le type de la valeur retournée par le pointeur de fonction.
Quelqu'un a-t-il un idée pour n'autoriser que la conversion T -> void et les
conversions légales autorisées par static_cast<> ?
Merci pour votre aide, toujours la bienvenue :)
Tout d'abord, helas dans le standard, il n'y a pas de conversion |
implicite d'un type pointeur de fonction vers un autre. Tu n'echapperas
a priori pas au reinterpret_cast.
C'est pas grave, tu peux toujours effectuer un controle de type
dynamique ou statique par les template qui sera cache a l'utilisateur.
On y verrait un peu plus clair si tu donnais le squelette de ta classe
template qui encapsule le tout?
Yannick
|
|
| Back to top |
|
 |
Frédéric Gourul Guest
|
Posted: Thu Jan 15, 2004 6:01 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
"Yannick Le goc" <legoc (AT) imag (DOT) fr> a écrit dans le message news:
bu6hil$t83$1 (AT) trompette (DOT) imag.fr...
| Quote: | Tu veux donc controler la conversion de T vers R et accepter certaines
conversions mais pas toutes et ce a la compilation. Ces choix etant
purement arbitraires, une solution est donc de faire planter le compilo
qd on le veut bien.
|
Ben j'avais pas l'impression que c'était aussi arbitraire que ca:
admettons que ce soit arbitraire pour les pointeurs<void> qui peuvent
accepter des fonctions retournant qqchose, j'admet que c'est un peu
cavalier... je peux m'en passer, mais je trouvais ca bien pratique.
par contre, les autres conversions que je voudrais autoriser, ce n'est que
de l'upcast.
j'ai bien le droit de faire, si B hérite de A:
A* A::getInstance() {return this;}
B* B::getInstance() {return this;}
A* pa = a.getInstance();
A* pb = b.getInstance();
alors naturellement j'aimerai aussi pouvoir faire:
A* (A::* pfa)() = &A::getInstance;
A* pa = (*pfa)();
A* (B::* pfb)() = &B::getInstance;
A* pb = (*pfb)();
| Quote: | Une maniere de le faire(sans doute la seule) est de se baser sur la
specialisation partielle de classe incomplete, mais en fait c'est
complique d'autant que dans ton cas c'est un constructeur qu'il faut
specialiser partiellement, interdit par le standard.
Donc si tu es motive, plonges-toi dans les templates avances ou bien
tout simplement fais une erreur a l'execution!
Yannick
petit exemple pour une classe:
|
[snip] // exemple à étudier et à essayer de comprendre... :)
| Quote: |
=> ici on a decide de n'accepter que A == B pour myclass. Donc
myclass<A, A> sera ok mais myclass<A, B> (A != B) provoquera une erreur
du compilateur (test<A, B, false> non definie).
on peut specialiser plus finement conv pour accepter ou rejeter d'autres
types de couple (A, B) mais ce n'est pas simple!
|
Effectivement, ca m'a l'air trop compliqué et je pense que ca va trop loin
pour ce que je veux. Si ca avait été possible facilement j'aurai laissé
cette possibilité, mais là je préfère avoir qqchose d'un peu plus
contraignant que quelque chose qui autorise n'importe quoi...
Merci encore.
Fred.
|
|
| Back to top |
|
 |
Yannick Le goc Guest
|
Posted: Thu Jan 15, 2004 6:10 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
Frédéric Gourul wrote:
| Quote: | "Yannick Le goc" <legoc (AT) imag (DOT) fr> a écrit dans le message news:
bu6954$jpl$1 (AT) trompette (DOT) imag.fr...
Tout d'abord, helas dans le standard, il n'y a pas de conversion
implicite d'un type pointeur de fonction vers un autre. Tu n'echapperas
a priori pas au reinterpret_cast.
C'est pas grave, tu peux toujours effectuer un controle de type
dynamique ou statique par les template qui sera cache a l'utilisateur.
J'aimerai bien en effet faire contrôler les types au compilateur, car je
veux qu'une conversion "non autorisée" soit rejetée par le compilateur. Je
n'ai aucune idée de la manière dont on peut faire ca...
On y verrait un peu plus clair si tu donnais le squelette de ta classe
template qui encapsule le tout?
La voilà:
template <class C, typename R
class PTest
{
private:
C* c;
R(C::*pf)();
public:
PTest(C* c, R(C::*m)()) :c(c), pf(m) {}
template
PTest(C* c, T(C::*m)()) :c(c)
{
// contrôles de conversion: T -> R
pf = reinterpret_cast<R(C::*)()>(m);
}
virtual R operator()() {return (c->*pf)();}
};
Et voici de quoi tester. Actuellement, tout est permis par le compilo :(
CTest c;
CTestD d;
PTest<CTest, void> pt0(&c, &CTest::foo); // valide
PTest<CTest, int> pt1(&c, &CTest::foo); // invalide
PTest<CTest, int> pt2(&c, &CTest::foo2); // valide
PTest<CTest, void> pt3(&c, &CTest::foo2); // valide
PTest<CTestD, CTestD*> pt4(&d, &CTestD::foo3); // valide
PTest<CTestD, CTest*> pt5(&d, &CTestD::foo3); // valide
PTest<CTest, CTestD*> pt6(&c, &CTest::foo3); // invalide
Merci pour ton aide:
Tu veux donc controler la conversion de T vers R et accepter certaines |
conversions mais pas toutes et ce a la compilation. Ces choix etant
purement arbitraires, une solution est donc de faire planter le compilo
qd on le veut bien.
Une maniere de le faire(sans doute la seule) est de se baser sur la
specialisation partielle de classe incomplete, mais en fait c'est
complique d'autant que dans ton cas c'est un constructeur qu'il faut
specialiser partiellement, interdit par le standard.
Donc si tu es motive, plonges-toi dans les templates avances ou bien
tout simplement fais une erreur a l'execution!
Yannick
petit exemple pour une classe:
template<class T, class U>
struct conv
{
enum {result = false};
};
template<class T>
struct conv<T, T>
{
enum {result = true};
};
template<class A, class B, bool ok>
struct test;
template<class A, class B>
struct test<A, B, true>
{
};
template<class A, class B>
class myclass : public test<A, B, conv
{
};
=> ici on a decide de n'accepter que A == B pour myclass. Donc
myclass<A, A> sera ok mais myclass<A, B> (A != B) provoquera une erreur
du compilateur (test<A, B, false> non definie).
on peut specialiser plus finement conv pour accepter ou rejeter d'autres
types de couple (A, B) mais ce n'est pas simple!
Yannick
|
|
| Back to top |
|
 |
Loïc Joly Guest
|
Posted: Thu Jan 15, 2004 10:16 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
Frédéric Gourul wrote:
[...]
| Quote: | j'aimerai pouvoir transmettre à pf des fonctions ayant une valeur de retour
de n'importe quel type puisque je ne l'exploite pas au travers de mon
pointeur.
Tu ne peux pas. Du moins pas directement, mais des classe comme |
boost::fonction te permettent de faire comme si.
En l'occurence, pourquoi vouloir réinventer une roue qui tourne à peu
près rond ?
--
Loïc
|
|
| Back to top |
|
 |
Frédéric Gourul Guest
|
Posted: Thu Jan 15, 2004 10:23 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
"Yannick Le goc" <legoc (AT) imag (DOT) fr> a écrit dans le message de
news:bu6hil$t83$1 (AT) trompette (DOT) imag.fr...
| Quote: | Une maniere de le faire(sans doute la seule) est de se baser sur la
specialisation partielle de classe incomplete, mais en fait c'est
complique d'autant que dans ton cas c'est un constructeur qu'il faut
specialiser partiellement, interdit par le standard.
|
Juste une question, si ca n'avais pas été un constructeur, la spécialisation
partielle aurait été plus simple ? Car, au final, ca ne sera pas au niveau
du constructeur dont j'en aurais besoin, mais dans la méthode qui connecte
la fonction au foncteur.
Et il y a un moyen pour vérifier à la compilation qu'une classe est bien une
dérivée d'une autre ?
|
|
| Back to top |
|
 |
Frédéric Gourul Guest
|
Posted: Thu Jan 15, 2004 10:33 pm Post subject: Re: cast & pointeurs de fonction... |
|
|
"Loïc Joly" <loic.actarus.joly (AT) wanadoo (DOT) fr> a écrit dans le message de
news:bu73dq$gq0$1 (AT) news-reader1 (DOT) wanadoo.fr...
| Quote: | Frédéric Gourul wrote:
Tu ne peux pas. Du moins pas directement, mais des classe comme
boost::fonction te permettent de faire comme si.
En l'occurence, pourquoi vouloir réinventer une roue qui tourne à peu
près rond ?
|
J'étais sur que quelqu'un me dirait cela. Je sais que boost le fait et c'est
d'ailleurs grâce à toi que je le sais, je l'avais vu dans ton exemple (cf.
post d'hier). Mais j'aime comprendre comment les choses fonctionnent, et
réinventer la roue me permet de me fixer les idées lorsque j'utilise qqchose
de nouveau. Et puis ca me permet, lorsque j'utilise une autre roue
(meilleure que la mienne), de savoir qu'elle n'aurait pas fonctionnée si
elle était carrée :)
Fred.
|
|
| Back to top |
|
 |
Frédéric Gourul Guest
|
Posted: Fri Jan 16, 2004 8:41 am Post subject: Re: cast & pointeurs de fonction... |
|
|
"Yannick Le goc" <legoc (AT) imag (DOT) fr> a écrit dans le message news:
bu84n4$lkm$1 (AT) trompette (DOT) imag.fr...
| Quote: | constructeur ou methode c'est la meme chose, on ne specialise
partiellement que des classes ou structures.
|
C'est ce que j'ai vu grâce aux pistes que tu m'as données.
Du coup, j'ai fait une spécialisation partielle de ma classe dans le cas où
le type de retour est "void". C'est une solution, certes un peu lourde, mais
tout à fait satisfaisante pour moi.
| Quote: | Verifier a la compilation
qu'une classe derive d'une autre peut se faire mais la aussi c'est
difficile. Alexandrescu propose dans "modern c++ design" une maniere de
le faire.
|
Je crois que je vais laisser tomber ce point pour l'instant, mais je note
qu'il a peut-être une possibilité de le faire...
Merci.
|
|
| Back to top |
|
 |
Yannick Le goc Guest
|
Posted: Fri Jan 16, 2004 8:43 am Post subject: Re: cast & pointeurs de fonction... |
|
|
Frédéric Gourul wrote:
| Quote: | "Yannick Le goc" <legoc (AT) imag (DOT) fr> a écrit dans le message de
news:bu6hil$t83$1 (AT) trompette (DOT) imag.fr...
Une maniere de le faire(sans doute la seule) est de se baser sur la
specialisation partielle de classe incomplete, mais en fait c'est
complique d'autant que dans ton cas c'est un constructeur qu'il faut
specialiser partiellement, interdit par le standard.
Juste une question, si ca n'avais pas été un constructeur, la spécialisation
partielle aurait été plus simple ? Car, au final, ca ne sera pas au niveau
du constructeur dont j'en aurais besoin, mais dans la méthode qui connecte
la fonction au foncteur.
Et il y a un moyen pour vérifier à la compilation qu'une classe est bien une
dérivée d'une autre ?
constructeur ou methode c'est la meme chose, on ne specialise |
partiellement que des classes ou structures. Verifier a la compilation
qu'une classe derive d'une autre peut se faire mais la aussi c'est
difficile. Alexandrescu propose dans "modern c++ design" une maniere de
le faire.
Yannick
|
|
| 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
|
|