j'essaye de faire quelque chose qui ne fonctionne pas :
j'aimerais avoir une classe de base qui permette de définir une
opération "appel de fonction" sur une instance, la fonction étant
identifiée par une chaîne.
L'implantation de l'appel de fonction est fait dans des classes dérivées
de la classe de base qui met en place le mécanisme d'association
chaîne <-> fonction.
L'instance citée plus haut est d'un type paramètré : je veux pouvoir
mettre en oeuvre le mécanisme sur des objets divers et variés.
J'ai commencé à implanter ça via des pointeurs sur fonction membre,
mais c'était oublier que le type connu dans la classe de base est
Base::*() et non pas Derivee::*(), et que si je peux écrire :
Derivee * d;
Base * b = d;
Je ne peux pas écrire :
void (Derivee::*g)();
void (Base::*f)() = g;
qui donne l'erreur :
error C2440: 'initializing' : cannot convert from 'void (__thiscall
Derivee::*)(void)' to 'void (__thiscall Base::*)(void)'
Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast
Le code ci-dessous donne une autre version de cette même erreur :
error C2664: 'associe' : cannot convert parameter 2 from 'class Variable
*(__thiscall RepresentantObjet::*)(void) const' to 'class Variable
*(__thiscall Representant<class Objet>::*)(void) const'
Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast
voilà mon code actuel :
===
#include <map>
#include <string>
class Variable {};
class Objet
{
public:
Variable * a() const { return new Variable; }
Variable * b() const { return new Variable; }
Variable * c() const { return new Variable; }
};
template <typename T>
class Representant
{
protected:
typedef Variable* (Representant::*Func)() const;
typedef std::map<std::string, Func> Fonctions;
T & m_instance;
class RepresentantObjet : Representant<Objet>
{
private: // accès depuis la classe de base via un pointeur...à voir
Variable * doA() const { return m_instance.a(); }
Variable * doB() const { return m_instance.b(); }
Variable * doC() const { return m_instance.c(); }
protected:
/* virtual */ void doInitialize()
{
associe("A", &RepresentantObjet::doA);
associe("B", &RepresentantObjet::doB);
associe("C", &RepresentantObjet::doC);
}
public:
RepresentantObjet(Objet& instance) : Representant<Objet>(instance) {}
};
===
j'ai cherché un pattern qui correspondrait, plutôt que de réinventer
la roue, car le problème me semble assez simple et probablement courant,
mais je n'ai pas trouvé pour l'instant.
Ce que je souhaite pouvoir écrire :
Objet o;
Representant<T>* r = new RepresentantObjet(o);
RepresentantObjet::initialize(*r); // appelé une unique fois en début de
// programme.
Variable * var = r->call("A"); // la substantifique moëlle : on
// appelle "A" sur l'objet dont on a le représentant pointé par r,
// peu importe ce qu'il représente réellement.
je souhaite bien évidemment ne pas devoir réécrire le mécanisme pour
chaque type de représentant.
une idée ? des idées ? plein d'idées ?
--
Stanislas RENAN
"Stanislas RENAN" a écrit dans le message de news: 41deb138$0$5715$
écrire : Representant<T>* r = new RepresentantObjet(o); n'est pas possible.
Il faut que tes templates héritent tous d'une classe de base :
class RepresentantObject;
template< class T > Representant : public RepresentantObject { ... };
Stanislas RENAN
Il faut que tes templates héritent tous d'une classe de base :
oui, c'est ce que je viens de faire, en me rendant compte que instanciation de classes implique que les classes instanciées n'ont aucun lien entre elles, sinon l'écriture du code source.
// Représentant de base template <typename T> class Representant : public RepresentantIf { // ... };
Maintenant, j'ai une spécialisation de fonction virtuelle de mon fonctor qui n'est pas prise en compte, et je bloque dessus. Visiblement, mon code est de nouveau incorrect :
// Functor dérivé A class RepresentantFunctorA : public RepresentantFunctor<Objet> { public: RepresentantFunctorA() : RepresentantFunctor<Objet>("A") {} Variable * operator()(const Objet& t) const { return t.a(); } };
un appel à operator()(const Objet&) sur une instance de RepresentantFunctorA via un pointeur sur la classe template de base RepresentantFunctor<Objet> appelle :
C'est ce qui m'agace un peu dans C++ : c'est très puissant, mais on est obligé d'écrire parfois des choses alambiquées pour implanter un concept a priori simple. Enfin, alambiquées pour moi, qui n'a pas :) Et en plus, là, ça ne fonctionne pas.
Je sens que je vais oublier la paramètrisation template, et faire une petite hiérarchie toute simple, plus lisible, et qui fonctionne :( -- Stanislas RENAN
Il faut que tes templates héritent tous d'une classe de base :
oui, c'est ce que je viens de faire, en me rendant compte que
instanciation de classes implique que les classes instanciées n'ont
aucun lien entre elles, sinon l'écriture du code source.
// Représentant de base
template <typename T>
class Representant : public RepresentantIf
{
// ...
};
Maintenant, j'ai une spécialisation de fonction virtuelle de mon fonctor
qui n'est pas prise en compte, et je bloque dessus.
Visiblement, mon code est de nouveau incorrect :
// Functor dérivé A
class RepresentantFunctorA : public RepresentantFunctor<Objet>
{
public:
RepresentantFunctorA() : RepresentantFunctor<Objet>("A") {}
Variable * operator()(const Objet& t) const { return t.a(); }
};
un appel à operator()(const Objet&) sur une instance de
RepresentantFunctorA via un pointeur sur la classe template de base
RepresentantFunctor<Objet> appelle :
C'est ce qui m'agace un peu dans C++ : c'est très puissant, mais on est
obligé d'écrire parfois des choses alambiquées pour implanter un concept
a priori simple.
Enfin, alambiquées pour moi, qui n'a pas :)
Et en plus, là, ça ne fonctionne pas.
Je sens que je vais oublier la paramètrisation template, et faire une
petite hiérarchie toute simple, plus lisible, et qui fonctionne :(
--
Stanislas RENAN
Il faut que tes templates héritent tous d'une classe de base :
oui, c'est ce que je viens de faire, en me rendant compte que instanciation de classes implique que les classes instanciées n'ont aucun lien entre elles, sinon l'écriture du code source.
// Représentant de base template <typename T> class Representant : public RepresentantIf { // ... };
Maintenant, j'ai une spécialisation de fonction virtuelle de mon fonctor qui n'est pas prise en compte, et je bloque dessus. Visiblement, mon code est de nouveau incorrect :
// Functor dérivé A class RepresentantFunctorA : public RepresentantFunctor<Objet> { public: RepresentantFunctorA() : RepresentantFunctor<Objet>("A") {} Variable * operator()(const Objet& t) const { return t.a(); } };
un appel à operator()(const Objet&) sur une instance de RepresentantFunctorA via un pointeur sur la classe template de base RepresentantFunctor<Objet> appelle :
C'est ce qui m'agace un peu dans C++ : c'est très puissant, mais on est obligé d'écrire parfois des choses alambiquées pour implanter un concept a priori simple. Enfin, alambiquées pour moi, qui n'a pas :) Et en plus, là, ça ne fonctionne pas.
Je sens que je vais oublier la paramètrisation template, et faire une petite hiérarchie toute simple, plus lisible, et qui fonctionne :( -- Stanislas RENAN
// Functor dérivé A class RepresentantFunctorA : public RepresentantFunctor<Objet> { public: RepresentantFunctorA() : RepresentantFunctor<Objet>("A") {} Variable * operator()(const Objet& t) const { return t.a(); } };
un appel à operator()(const Objet&) sur une instance de RepresentantFunctorA via un pointeur sur la classe template de base RepresentantFunctor<Objet> appelle :
J'ai quelques petites questions à te poser : - Déjà, je n'ai pas compris ce que tu veux en fait... - De ce que j'ai compris, je me demande si boost::bind n'a pas un effet semblable - Pourquoi RepresentantFunctorA n'est-il pas templaté ? - Je n'arrive pas à reproduire ton problème. Voici mon code : #include <iostream> using namespace std;
class Object{};
template <class T> struct A { virtual int operator()(T const &) {return 1;} };
// Functor dérivé A
class RepresentantFunctorA : public RepresentantFunctor<Objet>
{
public:
RepresentantFunctorA() : RepresentantFunctor<Objet>("A") {}
Variable * operator()(const Objet& t) const { return t.a(); }
};
un appel à operator()(const Objet&) sur une instance de
RepresentantFunctorA via un pointeur sur la classe template de base
RepresentantFunctor<Objet> appelle :
J'ai quelques petites questions à te poser :
- Déjà, je n'ai pas compris ce que tu veux en fait...
- De ce que j'ai compris, je me demande si boost::bind n'a pas un effet
semblable
- Pourquoi RepresentantFunctorA n'est-il pas templaté ?
- Je n'arrive pas à reproduire ton problème. Voici mon code :
#include <iostream>
using namespace std;
class Object{};
template <class T> struct A
{
virtual int operator()(T const &) {return 1;}
};
// Functor dérivé A class RepresentantFunctorA : public RepresentantFunctor<Objet> { public: RepresentantFunctorA() : RepresentantFunctor<Objet>("A") {} Variable * operator()(const Objet& t) const { return t.a(); } };
un appel à operator()(const Objet&) sur une instance de RepresentantFunctorA via un pointeur sur la classe template de base RepresentantFunctor<Objet> appelle :
J'ai quelques petites questions à te poser : - Déjà, je n'ai pas compris ce que tu veux en fait... - De ce que j'ai compris, je me demande si boost::bind n'a pas un effet semblable - Pourquoi RepresentantFunctorA n'est-il pas templaté ? - Je n'arrive pas à reproduire ton problème. Voici mon code : #include <iostream> using namespace std;
class Object{};
template <class T> struct A { virtual int operator()(T const &) {return 1;} };
int main() { A<Object> *a = new B; Object o; cout << a->operator()(o) << endl; cin.ignore(); }
Repondre sur le NG
J'ai quelques petites questions à te poser : - Déjà, je n'ai pas compris ce que tu veux en fait... j'ai des objets quelconques qui représentent des données.
Je veux pouvoir permettre à un utilisateur d'accéder à ces donnée s via un mécanisme générique et nommé.
Par exemple si la classe A possède 2 fonctions f et g renvoyant l'une u n double et l'autre une chaîne, il doit pouvoir accéder à ces informations. On doit lui présenter "f" et "g".
Ensuite, une fois qu'il a sélectionné ou bien "f" ou bien "g", il fau t être en mesure d'effectuer l'opération f() ou g(), et d'obtenir la valeur.
Les valeurs sont gérées par une classe Variable non développée ic i. Je cherche à implanter ce que j'ai appelé un représentant de A, et notament de A::f() et de A::g().
Je veux pouvoir représenter n'importe quoi, et obtenir un mécanisme unique qui permette de traiter la valeur de retour, quel que soit ce qui est représenté et le type de la valeur de retour. Je veux que ce mécanisme soit simple à étendre, tant dans les class es à représenter que dans les fonctions des classes représentées.
Le problème est simple dans la mesure où tout est connu à la compilation, et qu'on ne représente que des données, donc cela revien t à une fonction sans argument.
- De ce que j'ai compris, je me demande si boost::bind n'a pas un effet semblable Je n'ai pas eu le temps de regarder toutes les bibliothèques de boost,
tellement c'est riche et complexe. En jetant un oeil sur boost::bind, je n'ai pas vraiment l'impression que ce soit ce que je veux faire.
Chaque RepresentantFunctorQQCHOSE est différent des autres, et n'est pas destiné à être paramètré dans la mesure où il est le lien final entre le représentant et la donnée représentée.
- Je n'arrive pas à reproduire ton problème. Voici mon code : Je ne peux pas accéder à mon code ce WE.
Je voulais confirmer le comportement en le compilant avec comeau en ligne, mais je n'ai pas eu le temps. Je le ferai lundi.
Si effectivement cela fonctionne, alors mon compilateur est buggé. Ça ne serait pas impossible (c'est VC++ 6.0), mais ce qui est le plus souvent source d'erreur, c'est moi-même :) -- Stanislas RENAN
J'ai quelques petites questions à te poser :
- Déjà, je n'ai pas compris ce que tu veux en fait...
j'ai des objets quelconques qui représentent des données.
Je veux pouvoir permettre à un utilisateur d'accéder à ces donnée s via
un mécanisme générique et nommé.
Par exemple si la classe A possède 2 fonctions f et g renvoyant l'une u n
double et l'autre une chaîne, il doit pouvoir accéder à ces
informations.
On doit lui présenter "f" et "g".
Ensuite, une fois qu'il a sélectionné ou bien "f" ou bien "g", il fau t
être en mesure d'effectuer l'opération f() ou g(), et d'obtenir la
valeur.
Les valeurs sont gérées par une classe Variable non développée ic i.
Je cherche à implanter ce que j'ai appelé un représentant de A, et
notament de A::f() et de A::g().
Je veux pouvoir représenter n'importe quoi, et obtenir un mécanisme
unique qui permette de traiter la valeur de retour, quel que soit ce qui
est représenté et le type de la valeur de retour.
Je veux que ce mécanisme soit simple à étendre, tant dans les class es à
représenter que dans les fonctions des classes représentées.
Le problème est simple dans la mesure où tout est connu à la
compilation, et qu'on ne représente que des données, donc cela revien t à
une fonction sans argument.
- De ce que j'ai compris, je me demande si boost::bind n'a pas un effet
semblable
Je n'ai pas eu le temps de regarder toutes les bibliothèques de boost,
tellement c'est riche et complexe. En jetant un oeil sur boost::bind, je
n'ai pas vraiment l'impression que ce soit ce que je veux faire.
Chaque RepresentantFunctorQQCHOSE est différent des autres, et n'est
pas destiné à être paramètré dans la mesure où il est le lien final
entre le représentant et la donnée représentée.
- Je n'arrive pas à reproduire ton problème. Voici mon code :
Je ne peux pas accéder à mon code ce WE.
Je voulais confirmer le comportement en le compilant avec comeau en
ligne, mais je n'ai pas eu le temps. Je le ferai lundi.
Si effectivement cela fonctionne, alors mon compilateur est buggé.
Ça ne serait pas impossible (c'est VC++ 6.0), mais ce qui est le plus
souvent source d'erreur, c'est moi-même :)
--
Stanislas RENAN
J'ai quelques petites questions à te poser : - Déjà, je n'ai pas compris ce que tu veux en fait... j'ai des objets quelconques qui représentent des données.
Je veux pouvoir permettre à un utilisateur d'accéder à ces donnée s via un mécanisme générique et nommé.
Par exemple si la classe A possède 2 fonctions f et g renvoyant l'une u n double et l'autre une chaîne, il doit pouvoir accéder à ces informations. On doit lui présenter "f" et "g".
Ensuite, une fois qu'il a sélectionné ou bien "f" ou bien "g", il fau t être en mesure d'effectuer l'opération f() ou g(), et d'obtenir la valeur.
Les valeurs sont gérées par une classe Variable non développée ic i. Je cherche à implanter ce que j'ai appelé un représentant de A, et notament de A::f() et de A::g().
Je veux pouvoir représenter n'importe quoi, et obtenir un mécanisme unique qui permette de traiter la valeur de retour, quel que soit ce qui est représenté et le type de la valeur de retour. Je veux que ce mécanisme soit simple à étendre, tant dans les class es à représenter que dans les fonctions des classes représentées.
Le problème est simple dans la mesure où tout est connu à la compilation, et qu'on ne représente que des données, donc cela revien t à une fonction sans argument.
- De ce que j'ai compris, je me demande si boost::bind n'a pas un effet semblable Je n'ai pas eu le temps de regarder toutes les bibliothèques de boost,
tellement c'est riche et complexe. En jetant un oeil sur boost::bind, je n'ai pas vraiment l'impression que ce soit ce que je veux faire.
Chaque RepresentantFunctorQQCHOSE est différent des autres, et n'est pas destiné à être paramètré dans la mesure où il est le lien final entre le représentant et la donnée représentée.
- Je n'arrive pas à reproduire ton problème. Voici mon code : Je ne peux pas accéder à mon code ce WE.
Je voulais confirmer le comportement en le compilant avec comeau en ligne, mais je n'ai pas eu le temps. Je le ferai lundi.
Si effectivement cela fonctionne, alors mon compilateur est buggé. Ça ne serait pas impossible (c'est VC++ 6.0), mais ce qui est le plus souvent source d'erreur, c'est moi-même :) -- Stanislas RENAN
Loïc Joly
Repondre sur le NG wrote:
J'ai quelques petites questions à te poser : - Déjà, je n'ai pas compris ce que tu veux en fait...
j'ai des objets quelconques qui représentent des données. Je veux pouvoir permettre à un utilisateur d'accéder à ces données via un mécanisme générique et nommé.
Par exemple si la classe A possède 2 fonctions f et g renvoyant l'une un double et l'autre une chaîne, il doit pouvoir accéder à ces informations. On doit lui présenter "f" et "g".
Ensuite, une fois qu'il a sélectionné ou bien "f" ou bien "g", il faut être en mesure d'effectuer l'opération f() ou g(), et d'obtenir la valeur.
Les valeurs sont gérées par une classe Variable non développée ici. Je cherche à implanter ce que j'ai appelé un représentant de A, et notament de A::f() et de A::g().
Je veux pouvoir représenter n'importe quoi, et obtenir un mécanisme unique qui permette de traiter la valeur de retour, quel que soit ce qui est représenté et le type de la valeur de retour. Je veux que ce mécanisme soit simple à étendre, tant dans les classes à représenter que dans les fonctions des classes représentées.
Le problème est simple dans la mesure où tout est connu à la compilation, et qu'on ne représente que des données, donc cela revient à une fonction sans argument.
Ce n'est pas encore hyper clair, mais c'est mieux. Je vais essayer de reformuler, voir si j'ai bien compris.
Tu as une classe A : struct A { Valeur f(); Valeur g(); };
Tu veux une classe RepresentantA struct RepresentantA { RepresenantantA (A* vraieDonnee); A* myA; Valeur call(string name); };
Et tu veux pourvoir écrire :
A a; RepresentantA ra(&a); Valeur v = ra.call("f"); // équivalent à Valeur v = a.f();
Je ne sais pas si ça peut aider, ou si je suis totalement à côté de la plaque...
-- Loïc
Repondre sur le NG wrote:
J'ai quelques petites questions à te poser :
- Déjà, je n'ai pas compris ce que tu veux en fait...
j'ai des objets quelconques qui représentent des données.
Je veux pouvoir permettre à un utilisateur d'accéder à ces données via
un mécanisme générique et nommé.
Par exemple si la classe A possède 2 fonctions f et g renvoyant l'une un
double et l'autre une chaîne, il doit pouvoir accéder à ces
informations.
On doit lui présenter "f" et "g".
Ensuite, une fois qu'il a sélectionné ou bien "f" ou bien "g", il faut
être en mesure d'effectuer l'opération f() ou g(), et d'obtenir la
valeur.
Les valeurs sont gérées par une classe Variable non développée ici.
Je cherche à implanter ce que j'ai appelé un représentant de A, et
notament de A::f() et de A::g().
Je veux pouvoir représenter n'importe quoi, et obtenir un mécanisme
unique qui permette de traiter la valeur de retour, quel que soit ce qui
est représenté et le type de la valeur de retour.
Je veux que ce mécanisme soit simple à étendre, tant dans les classes à
représenter que dans les fonctions des classes représentées.
Le problème est simple dans la mesure où tout est connu à la
compilation, et qu'on ne représente que des données, donc cela revient à
une fonction sans argument.
Ce n'est pas encore hyper clair, mais c'est mieux. Je vais essayer de
reformuler, voir si j'ai bien compris.
Tu as une classe A :
struct A
{
Valeur f();
Valeur g();
};
Tu veux une classe RepresentantA
struct RepresentantA
{
RepresenantantA (A* vraieDonnee);
A* myA;
Valeur call(string name);
};
Et tu veux pourvoir écrire :
A a;
RepresentantA ra(&a);
Valeur v = ra.call("f"); // équivalent à Valeur v = a.f();
J'ai quelques petites questions à te poser : - Déjà, je n'ai pas compris ce que tu veux en fait...
j'ai des objets quelconques qui représentent des données. Je veux pouvoir permettre à un utilisateur d'accéder à ces données via un mécanisme générique et nommé.
Par exemple si la classe A possède 2 fonctions f et g renvoyant l'une un double et l'autre une chaîne, il doit pouvoir accéder à ces informations. On doit lui présenter "f" et "g".
Ensuite, une fois qu'il a sélectionné ou bien "f" ou bien "g", il faut être en mesure d'effectuer l'opération f() ou g(), et d'obtenir la valeur.
Les valeurs sont gérées par une classe Variable non développée ici. Je cherche à implanter ce que j'ai appelé un représentant de A, et notament de A::f() et de A::g().
Je veux pouvoir représenter n'importe quoi, et obtenir un mécanisme unique qui permette de traiter la valeur de retour, quel que soit ce qui est représenté et le type de la valeur de retour. Je veux que ce mécanisme soit simple à étendre, tant dans les classes à représenter que dans les fonctions des classes représentées.
Le problème est simple dans la mesure où tout est connu à la compilation, et qu'on ne représente que des données, donc cela revient à une fonction sans argument.
Ce n'est pas encore hyper clair, mais c'est mieux. Je vais essayer de reformuler, voir si j'ai bien compris.
Tu as une classe A : struct A { Valeur f(); Valeur g(); };
Tu veux une classe RepresentantA struct RepresentantA { RepresenantantA (A* vraieDonnee); A* myA; Valeur call(string name); };
Et tu veux pourvoir écrire :
A a; RepresentantA ra(&a); Valeur v = ra.call("f"); // équivalent à Valeur v = a.f();
Je ne sais pas si ça peut aider, ou si je suis totalement à côté de la plaque...
-- Loïc
Stanislas RENAN
Repondre sur le NG wrote: Ce n'est pas encore hyper clair, mais c'est mieux. Je vais essayer de reformuler, voir si j'ai bien compris.
Tu as une classe A : struct A { Valeur f(); Valeur g(); };
Tu veux une classe RepresentantA struct RepresentantA { RepresenantantA (A* vraieDonnee); A* myA; Valeur call(string name); };
Et tu veux pourvoir écrire :
A a; RepresentantA ra(&a); Valeur v = ra.call("f"); // équivalent à Valeur v = a.f();
C'est bien ça ? Presque, oui.
ra doit être un pointeur sur classe de base afin de pouvoir utiliser un représentant de façon "anonyme" :
RepresentantBase * rb = conteneur.getRepresentantReel(); Valeur v = rb.call("f");
getRepresentantReel() renvoyant une instance de RepresentantQQCH, via un pointeur sur la classe de base, RepresentantBase ici.
Par ailleurs, la correspondance entre la représentation et la fonction réelle doit être statique car elle est identique pour toutes les instances d'un représentant, il est donc inutile de la construire pour chaque instance.
Je ne sais pas si ça peut aider, ou si je suis totalement à côté de la plaque...
J'ai l'impression que ce que tu proposes correspond à ce que je veux, même si je n'en suis pas encore sûr car il faut que je potasse les bibliothèques BOOST tout d'abord (et j'ai un peu de mal, je l'avoue, ça n'est pas immédiat, d'autant plus que je ne connais pas la partie STL dédiée à cela [bind, ptr_fun, etc.] ).
Voici le code qui compile et fonctionne, et qui n'utilise pas BOOST :
== // representant.cpp : Defines the entry point for the console application. //
Objet o; RepresentantIf * r = new RepresentantObjet(o); RepresentantIf::init(*r); // appelé une unique fois en début de // programme. RepresentantObjet::s_rfa(o); RepresentantObjet::s_rfb(o); Variable * var = r->call(std::string("A")); // la substantifique moëlle : on // appelle "A" sur l'objet dont on a le représentant pointé par r, var = r->call(std::string("B")); // ici, on appelle "B"
return 0; } == le problème de virtuelle non appelée était dû à une erreur de ma part. J'avais un set d'objets de base, et je copiais dans ces objets des instances de classe dérivée. Il était donc normal que la fonction appelée fût celle de base !
Du fait de l'utilisation de pointeurs, je suis "obligé" de passer par une map pour faire les comparaisons sur les clefs. J'ai essayé de passer une fonction de comparaison de mon cru (en gros une spécialisation de less<T>(T cons * const X, T const * const Y) pour les pointeurs, qui compare *X et *Y au lieu de X et Y, mais du coup ça m'obligerait à construire un T temporaire avec la bonne chaîne pour utiliser set::find(). Finalement, je préfère une map, plus simple.
Le code ainsi écrit est assez difficile à lire et j'ai du mal à le manipuler pour l'instant (et dire que c'est moi qui l'ai écrit, je n'ose pas imaginer pour les autres).
Je trouve ta version beaucoup plus élégante... a priori (plus courte, plus simple, plus lisible, plus facile à étendre). Malheureusement, le problème, c'est qu'elle ne compile pas et que pour l'instant j'ai plutôt des erreurs de syntaxe et des internal compiler errors.
Comeau me dit par ailleurs que mon typedef template est erroné lorsque je compile en mode strict.
int main() { A a; RepresentantA ra(&a); Valeur * v = ra.call("f"); // équivalent à Valeur v = a.f();
return 0; } == mais ça explose à la compilation avec 1 million d'erreurs sur bind()... -- Stanislas RENAN
Repondre sur le NG wrote:
Ce n'est pas encore hyper clair, mais c'est mieux. Je vais essayer de
reformuler, voir si j'ai bien compris.
Tu as une classe A :
struct A
{
Valeur f();
Valeur g();
};
Tu veux une classe RepresentantA
struct RepresentantA
{
RepresenantantA (A* vraieDonnee);
A* myA;
Valeur call(string name);
};
Et tu veux pourvoir écrire :
A a;
RepresentantA ra(&a);
Valeur v = ra.call("f"); // équivalent à Valeur v = a.f();
C'est bien ça ?
Presque, oui.
ra doit être un pointeur sur classe de base afin de pouvoir utiliser
un représentant de façon "anonyme" :
RepresentantBase * rb = conteneur.getRepresentantReel();
Valeur v = rb.call("f");
getRepresentantReel() renvoyant une instance de RepresentantQQCH,
via un pointeur sur la classe de base, RepresentantBase ici.
Par ailleurs, la correspondance entre la représentation et la fonction
réelle doit être statique car elle est identique pour toutes les
instances d'un représentant, il est donc inutile de la construire pour
chaque instance.
Je ne sais pas si ça peut aider, ou si je suis totalement à côté de la
plaque...
J'ai l'impression que ce que tu proposes correspond à ce que je veux,
même si je n'en suis pas encore sûr car il faut que je potasse les
bibliothèques BOOST tout d'abord (et j'ai un peu de mal, je l'avoue, ça
n'est pas immédiat, d'autant plus que je ne connais pas la partie STL
dédiée à cela [bind, ptr_fun, etc.] ).
Voici le code qui compile et fonctionne, et qui n'utilise pas BOOST :
== // representant.cpp : Defines the entry point for the console application.
//
Objet o;
RepresentantIf * r = new RepresentantObjet(o);
RepresentantIf::init(*r); // appelé une unique fois en début de
// programme.
RepresentantObjet::s_rfa(o);
RepresentantObjet::s_rfb(o);
Variable * var = r->call(std::string("A")); // la substantifique
moëlle : on
// appelle "A" sur l'objet dont on a le représentant pointé par r,
var = r->call(std::string("B")); // ici, on appelle "B"
return 0;
}
==
le problème de virtuelle non appelée était dû à une erreur de ma part.
J'avais un set d'objets de base, et je copiais dans ces objets des
instances de classe dérivée. Il était donc normal que la fonction
appelée fût celle de base !
Du fait de l'utilisation de pointeurs, je suis "obligé" de passer par
une map pour faire les comparaisons sur les clefs. J'ai essayé de passer
une fonction de comparaison de mon cru (en gros une spécialisation de
less<T>(T cons * const X, T const * const Y) pour les pointeurs, qui
compare *X et *Y au lieu de X et Y, mais du coup ça m'obligerait à
construire un T temporaire avec la bonne chaîne pour utiliser
set::find().
Finalement, je préfère une map, plus simple.
Le code ainsi écrit est assez difficile à lire et j'ai du mal à le
manipuler pour l'instant (et dire que c'est moi qui l'ai écrit, je n'ose
pas imaginer pour les autres).
Je trouve ta version beaucoup plus élégante... a priori (plus courte,
plus simple, plus lisible, plus facile à étendre).
Malheureusement, le problème, c'est qu'elle ne compile pas et que pour
l'instant j'ai plutôt des erreurs de syntaxe et des internal compiler
errors.
Comeau me dit par ailleurs que mon typedef template est erroné lorsque
je compile en mode strict.
Repondre sur le NG wrote: Ce n'est pas encore hyper clair, mais c'est mieux. Je vais essayer de reformuler, voir si j'ai bien compris.
Tu as une classe A : struct A { Valeur f(); Valeur g(); };
Tu veux une classe RepresentantA struct RepresentantA { RepresenantantA (A* vraieDonnee); A* myA; Valeur call(string name); };
Et tu veux pourvoir écrire :
A a; RepresentantA ra(&a); Valeur v = ra.call("f"); // équivalent à Valeur v = a.f();
C'est bien ça ? Presque, oui.
ra doit être un pointeur sur classe de base afin de pouvoir utiliser un représentant de façon "anonyme" :
RepresentantBase * rb = conteneur.getRepresentantReel(); Valeur v = rb.call("f");
getRepresentantReel() renvoyant une instance de RepresentantQQCH, via un pointeur sur la classe de base, RepresentantBase ici.
Par ailleurs, la correspondance entre la représentation et la fonction réelle doit être statique car elle est identique pour toutes les instances d'un représentant, il est donc inutile de la construire pour chaque instance.
Je ne sais pas si ça peut aider, ou si je suis totalement à côté de la plaque...
J'ai l'impression que ce que tu proposes correspond à ce que je veux, même si je n'en suis pas encore sûr car il faut que je potasse les bibliothèques BOOST tout d'abord (et j'ai un peu de mal, je l'avoue, ça n'est pas immédiat, d'autant plus que je ne connais pas la partie STL dédiée à cela [bind, ptr_fun, etc.] ).
Voici le code qui compile et fonctionne, et qui n'utilise pas BOOST :
== // representant.cpp : Defines the entry point for the console application. //
Objet o; RepresentantIf * r = new RepresentantObjet(o); RepresentantIf::init(*r); // appelé une unique fois en début de // programme. RepresentantObjet::s_rfa(o); RepresentantObjet::s_rfb(o); Variable * var = r->call(std::string("A")); // la substantifique moëlle : on // appelle "A" sur l'objet dont on a le représentant pointé par r, var = r->call(std::string("B")); // ici, on appelle "B"
return 0; } == le problème de virtuelle non appelée était dû à une erreur de ma part. J'avais un set d'objets de base, et je copiais dans ces objets des instances de classe dérivée. Il était donc normal que la fonction appelée fût celle de base !
Du fait de l'utilisation de pointeurs, je suis "obligé" de passer par une map pour faire les comparaisons sur les clefs. J'ai essayé de passer une fonction de comparaison de mon cru (en gros une spécialisation de less<T>(T cons * const X, T const * const Y) pour les pointeurs, qui compare *X et *Y au lieu de X et Y, mais du coup ça m'obligerait à construire un T temporaire avec la bonne chaîne pour utiliser set::find(). Finalement, je préfère une map, plus simple.
Le code ainsi écrit est assez difficile à lire et j'ai du mal à le manipuler pour l'instant (et dire que c'est moi qui l'ai écrit, je n'ose pas imaginer pour les autres).
Je trouve ta version beaucoup plus élégante... a priori (plus courte, plus simple, plus lisible, plus facile à étendre). Malheureusement, le problème, c'est qu'elle ne compile pas et que pour l'instant j'ai plutôt des erreurs de syntaxe et des internal compiler errors.
Comeau me dit par ailleurs que mon typedef template est erroné lorsque je compile en mode strict.