OVH Cloud OVH Cloud

conversion string -> boost::function

9 réponses
Avatar
guillaume
bonsoir,

je cherche a convertir une string en boost::function.
basiquement, j ai une fonction:
void toto(boost::function<void (int)>);
et que je souhaite appeler avec un nom de fonction/methode recupere
dans un fichier par exemple:
<totos>
<toto>MaSuperClasse::pouet</toto>
<toto>maSuperFunction</toto>
</totos>

avez vous une idee comment faire ca?

merci par avance pour votre aide,

cordialement,

--
Guillaume Desticourt

9 réponses

Avatar
Marc Duflot
guillaume wrote:
bonsoir,

je cherche a convertir une string en boost::function.
basiquement, j ai une fonction:
void toto(boost::function<void (int)>);
et que je souhaite appeler avec un nom de fonction/methode recupere
dans un fichier par exemple:
<totos>
<toto>MaSuperClasse::pouet</toto>
<toto>maSuperFunction</toto>
</totos>

avez vous une idee comment faire ca?


Avec une map<string, function<void (int)> comme illustré ci-dessous :

#include <map>
#include <string>
#include <iostream>
#include <boost/function.hpp>

using namespace std;
using namespace boost;

typedef function<void (int)> function_type;
typedef map<string, function_type> factory_type;

void f1(int i) { cout << "f1 " << i << endl; }
void f2(int i) { cout << "f2 " << i << endl; }

int main()
{
factory_type factory;
factory["f1"] = &f1; // enregistrement
factory["f2"] = &f2; // "

factory["f1"](42); // appel qui écrit f1 42
}

En pratique, il est préférable d'encapsuler la map dans un objet, que
les fonctions s'enregistrent dans la map de manière transparente
en-dehors du main et il est nécessaire de gérer les erreurs dans le cas
où le nom de fonction cherché n'existe pas. Pour les fonctions membres,
il faut lier (avec boost::bind) la fonction membre à un objet du type
correspondant.

Marc

Avatar
guillaume
bonsoir,

je n ai pas du etre clair: je cherche a convertir une string en
boost::function
tu convertis une fonction en boost::function, ca c est bon je sais
faire :)

ce que je veux, c est recuperer le nom de ma fonction dans un fichier,
et ensuite la stocker dans la map - pour reprendre ton exemple.

je pense que je peux faire ca avec dlopen, mais c est du posix, donc je
me demandais si il existait des solutions portables/standards pour
faire ca.

cordialement,

--
Guillaume Desticourt
Avatar
kanze
guillaume wrote:

je n ai pas du etre clair: je cherche a convertir une string en
boost::function


Ce qui veut dire quoi, exactement. Quel est le rapport entre la
chaîne est l'objet fonctionnel que tu veux obtenir ?

tu convertis une fonction en boost::function, ca c est bon je
sais faire :)


Il a aussi créé un mapping std::string -> boost::function.

ce que je veux, c est recuperer le nom de ma fonction dans un
fichier, et ensuite la stocker dans la map - pour reprendre
ton exemple.


Encore : quel est le rapport entre le nom et la fonction ? À un
moment donné, il faut que tu etablisses ce rapport. On pourrait
imaginer, par exemple, que chaque fonction soit dans un objet
dynamique, que tu charges. Mais alors, il faudrait une
convention de nommage du fichier, etc.

je pense que je peux faire ca avec dlopen, mais c est du
posix, donc je me demandais si il existait des solutions
portables/standards pour faire ca.


Il n'y a rien dans le C++ standard en ce qui concerne les objets
chargés dynamiquement. Et en fait, l'approche Windows et
l'approche Unix est assez différente. Si c'est ça que tu veux,
je crains qu'il va falloir du code propre à chaque système.

--
James Kanze GABI Software
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
guillaume
hum je vais essayer d etre plus clair:

je fournis ca:
cat toto.cc

boost::function<void (int)> convertor(std::string functionName)
{
boost::function<void (int) > myFunction = xxx(functionName);
return myFunction;
}

j envoie toto.so a mon utilisateur et, lui, ecrit ca:
cat main.cc

void pouet(int)
{
std::cout << "pouet" << std::endl;
}

int main(void)
{
boost::function<void (int) >myFunction = convertor("pouet");
return 0;
}


voila j espere que c est clair. je ne suis pas familier de ce probleme,
mais je crois que ca s appelle de la reflexion et que ce n est pas
possible en c++

cordialement,

--
Guillaume Desticourt
Avatar
Loïc Joly


Il n'y a rien dans le C++ standard en ce qui concerne les objets
chargés dynamiquement. Et en fait, l'approche Windows et
l'approche Unix est assez différente.


Elles se sont un peu rapprochées il me semble avec les dernières
versions de gcc (en particulier, les noms ne sont plus exportés par défaut).

--
Loïc

Avatar
kanze
Loïc Joly wrote:

Il n'y a rien dans le C++ standard en ce qui concerne les
objets chargés dynamiquement. Et en fait, l'approche Windows
et l'approche Unix est assez différente.


Elles se sont un peu rapprochées il me semble avec les
dernières versions de gcc (en particulier, les noms ne sont
plus exportés par défaut).


Est-ce que ça ne dépendrait pas plutôt de l'éditeur de liens ?
Les noms doivent bien se retrouver au moins dans le fichier
objet (.o) ; sinon, on ne pouvait pas les linker statiquement.
Et une fois dans le fichier objet, c'est l'éditeur de liens (ou
l'outil qui construit l'objet dynamique) qui décide s'ils se
retrouve dans l'objet dynamique ou non.

Je ne sais pas comment ça marche sous Windows, mais je suppose
que le compilateur « marque » les symboles d'une façon ou d'une
autre, pour que l'éditeur de liens sait s'il faut les exposer
dans le .dll ou non. Pour que ça marche, il faut 1) que le
format du fichier objet permet un tel marquage, et 2) que
l'éditeur de liens s'en sert. Dans le cas général de g++ (sous
Solaris, par exemple), je ne suis pas sûr que le premier soit
donné, et le deuxième ne l'est certainement pas.

Et évidemment, une partie importante des différences se trouve
dans les différentes sémantiques de dlopen et dlsym par rapport
à LoadLibrary et GetProcAddress.

--
James Kanze GABI Software
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
kanze
guillaume wrote:

je fournis ca:
cat toto.cc

boost::function<void (int)> convertor(std::string functionName)
{
boost::function<void (int) > myFunction = xxx(functionName);
return myFunction;
}

j envoie toto.so a mon utilisateur et, lui, ecrit ca:
cat main.cc

void pouet(int)
{
std::cout << "pouet" << std::endl;
}

int main(void)
{
boost::function<void (int) >myFunction = convertor("pouet");
return 0;
}

voila j espere que c est clair. je ne suis pas familier de ce
probleme, mais je crois que ca s appelle de la reflexion et
que ce n est pas possible en c++


Tel que tu le décrit là, non. Mais je ne vois pas trop le
problème que tu essaies de résoudre. Si ton utilisateur a défini
la fonction, il pourrait très bien t'en passer son adresse, et
non seulement son nom symbolique. Et une fois tu en as les deux,
tu en fais ce que tu veux.

--
James Kanze GABI Software
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
guillaume
Mais je ne vois pas trop le problème que tu essaies de résoudre.

je souhaiterais que - presque - tout puisse se faire avec un fichier de
conf plutot que par ecriture de code de la part de mes utilisateurs

--
Guillaume Desticourt
Avatar
kanze
guillaume wrote:
Mais je ne vois pas trop le problème que tu essaies de
résoudre.


je souhaiterais que - presque - tout puisse se faire avec un
fichier de conf plutot que par ecriture de code de la part de
mes utilisateurs


OK, mais il ne va jamais pouvoir faire exécuter une fonction qui
ne fait pas partie de ton programme.

En fait, il est probable qu'il ne doit pas pouvoir exécuter la
plupart des fonctions -- seulement celles où tu as prévu
qu'elles puissent s'exécuter de cette façon. Du coup, une
régistration explicite dans un std::map fait l'affaire.

Il m'est arrivé de faire quelque chose de semblable en Java,
avec Class.forName( className ).newInstance(). Note bien, en
revanche, que je ne faisais l'économie que du map explicit -- si
la classe n'existait pas, j'avais une exception. Et afin de
l'utiliser, je convertissais le résultat immédiatement en la
classe de base qu'il me fallait, avec une autre possibilité
d'une exception. À la fin, je me démande si une régistration
explicite n'aurait pas été mieux.

Dernièrement, j'ai aussi fait un système avec registration
implicite paresseuse, qui marchait pas mal. Dans ce cas-là, les
fonctions (dans mon cas, plutôt des classes) se trouvait dans
des objets dynamiques ; si je ne trouvais pas la fonction dans
le tableau associatif, j'utilisais une convention de nommage
pour en trouver (ou non, évidemment) un objet dynamique, que je
chargeais, et dont je mettais l'adresse de l'objet dans le
tableau associatif, pour la prochaine fois. (D'un certain point
de vue, j'ai implémenté en C++ l'équivalent du Java
Class.forName( className ).newInstance. Mais avec pas mal de
restrictions : surtout, il ne trouvait pas n'importe quelle
classe dans l'application.)

--
James Kanze GABI Software
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