OVH Cloud OVH Cloud

existence d'une fonction

11 réponses
Avatar
Alain Cabiran
Bonjour,

le code suivant renvoie false, autrement dit
le test de definition du symbole fonction1
ne fonctionne pas avec la declaration d'une fonction.

#include <iostream>
#include <iomanip>

int fonction1() { return 1; }

#ifdef fonction1
bool fonction2() { return true; }
#else
bool fonction2() { return false; }
#endif

int main()
{
std::cout << "does #ifdef handle function names ? "
<< std::boolalpha
<< fonction2()
<< std::endl;
}

existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??

merci d'avance pour toute piste

Alain Cabiran

10 réponses

1 2
Avatar
Matthieu Moy
Alain Cabiran writes:

Bonjour,


Bonjour,

int fonction1() { return 1; }


=> Une fonction C/C++

#ifdef fonction1


=> Un test sur une constante du préprocesseur.

Le préprocesseur passe avant le compilateur (d'ou son nom), et ne
traite que les lignes commençant par "#", les commentaires, et les
expansions de macros. Il ne connait pas le concept de fonction, donc,
il ne peut pas dire "oui" ici.

existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??


Oui : Coder en lisp !

Plus sérieusement, a l'execution, tu peux tester l'existance d'un
symbole via dlsym sur certaines plateformes (Linux par exemple) (mais
c'est assez sale comme façon de faire AMHA, et en C++, avec les
problèmes de mangling, tu n'est pas sorti de l'auberge). Mais ce que
tu étais en train de faire, c'est une detection à la compilation. Je
ne vois pas trop comment faire en C++, vu que si tu fais référence à
la fonction et qu'elle n'existe pas, ton code ne compilera pas ...

Avec des templates, par contre, tu peux tester l'existance d'un
template spécialisé. C'est peut-être une piste même si ça ne répond
pas vraiment à la question.

--
Matthieu

Avatar
Twxs
Alain Cabiran wrote:

existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??

merci d'avance pour toute piste

Alain Cabiran
pas avec des ifdef sur les noms de fonctions

une solution est de definir une macro ds le header de chaque fonction

fonction1.h

#define HAVE_FUNC_1
bool fonction1();


apres tu peux faire #ifdef HAVE_FUNC_1

une autre solution : exporter la fonction un coup de
getPRocAdress("focntion1") retournera NULL si elle n'est pas exporté

on peut imaginé d'autres mecanismes, comme l'utilisation de factory,
mais c'est pour faire quoi???

Avatar
Falk Tannhäuser
Alain Cabiran wrote:

existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??


C'est en tout cas possible avec les fonctions membres d'une
classe, qu'elles soient statiques ou non, en utilisant la
le principe SFINAE - à condition de disposer d'un compilateur
assez à jour par rapport à la Norme C++. Voici un petit exemple :
_________________________________________________________________
#include <iostream>

struct foo
{
static int fonction1() { return 0; }
int fonction2() { return 1; }
};

struct bar
{
int fonction1() { return 0; }
static int fonction2() { return 1; }
};

struct toto {};

template<int (*pfunc)()> struct wrap_fun;

template<typename T>
char helper_has_static_fonction1(T const&, wrap_fun<&T::fonction1>* = 0);

char (& helper_has_static_fonction1(...) )[2];

#define HAS_static_fonction1(t) (sizeof helper_has_static_fonction1(t) == sizeof(char))

template<typename T, int (T::*pfunc)()> struct wrap_memfun;

template<typename T>
char helper_has_mem_fonction2(T const&, wrap_memfun<T, &T::fonction2>* = 0);

char (& helper_has_mem_fonction2(...) )[2];

#define HAS_mem_fonction2(t) (sizeof helper_has_mem_fonction2(t) == sizeof(char))

int main()
{
foo* pf = 0;
bar* pb = 0;
toto* pt = 0;

#if 1 /////////////////////////////////////////
std::cout << std::boolalpha
<< HAS_static_fonction1(*pf) << ' '
<< HAS_static_fonction1(*pb) << ' '
#ifndef __GNUC__
<< HAS_static_fonction1(*pt) << ' '
<< HAS_static_fonction1(0) << ' '
#endif // __GNUC__
<< HAS_mem_fonction2(*pf) << ' '
<< HAS_mem_fonction2(*pb) << ' '
#ifndef __GNUC__
<< HAS_mem_fonction2(*pt) << ' '
<< HAS_mem_fonction2(0)
#endif // __GNUC__
<< 'n';

#else /////////////////////////////////////////
char a[HAS_static_fonction1(*pf)]; // Line 58 (OK)
char b[HAS_static_fonction1(*pb)]; // Line 59 (Error)
char c[HAS_static_fonction1(*pt)]; // Line 60 (Error)
char d[HAS_static_fonction1(0)]; // Line 61 (Error)
char e[HAS_mem_fonction2(*pf)]; // Line 62 (OK)
char f[HAS_mem_fonction2(*pb)]; // Line 63 (Error)
char g[HAS_mem_fonction2(*pt)]; // Line 64 (Error)
char h[HAS_mem_fonction2(0)]; // Line 65 (Error)

#endif /////////////////////////////////////////
return 0;
}
_________________________________________________________________

Cela compile et fonctionne correctement avec le compilo Comeau
en ligne <http://www.comeaucomputing.com/tryitout/> - bien que
cela ne permet pas d'exécuter le code généré, on peut vérifier
que HAS_static_fonction1() et HAS_mem_fonction2() renvoient
'true' et 'false' comme attendu en changeant le '#if 1' en
'#if 0'. On obtient des erreurs de compilation dans les lignes
59, 60, 61, 63, 64, 65 car la taille des tableaux définis dans
ces lignes vaut 0 (les lignes 58 et 62 passent).
L'intérêt des résultats 'bool' fournis par HAS_static_fonction1()
et HAS_mem_fonction2() est que ce sont des constantes de compilation,
qui permettent donc de spécialiser des templates en fonction de
la présence ou absence d'une fonction membre dans une classe.

Avec le gcc dont je dispose (version 3.3.3 sous CygWin), le
résultat est malheureusement moins brillant ; les lignes
comprises entre '#ifndef __GNUC__' ci dessus font des erreurs
de compilation si on devalide ce symbole de préprocesseur
(genre : "`fonctionX' is not a member of type `toto'" et
"`int' is not an aggregate type"), mais curieusement ça
passe pour la 'struct bar' (Affichage : "true false true false ").

Il serait intéressant de savoir comment se comportent des
gcc plus récents.

En revanche, je ne sais pas si cette technique pourrait être
étendue pour tester la présence des fonctions "libres"...

Falk

Avatar
Falk Tannhäuser
Alain Cabiran wrote:
Alain Cabiran wrote:

existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??



C'est en tout cas possible avec les fonctions membres d'une
classe, qu'elles soient statiques ou non, en utilisant
le principe SFINAE - à condition de disposer d'un compilateur
assez à jour par rapport à la Norme C++. Voici un petit exemple :
_________________________________________________________________
#include <iostream>

struct foo
{
static int fonction1() { return 0; }
int fonction2() { return 1; }
};

struct bar
{
int fonction1() { return 0; }
static int fonction2() { return 1; }
};

struct toto {};

template<int (*pfunc)()> struct wrap_fun;

template<typename T>
char helper_has_static_fonction1(T const&, wrap_fun<&T::fonction1>* = 0);

char (& helper_has_static_fonction1(...) )[2];

#define HAS_static_fonction1(t) (sizeof helper_has_static_fonction1(t) == sizeof(char))

template<typename T, int (T::*pfunc)()> struct wrap_memfun;

template<typename T>
char helper_has_mem_fonction2(T const&, wrap_memfun<T, &T::fonction2>* = 0);

char (& helper_has_mem_fonction2(...) )[2];

#define HAS_mem_fonction2(t) (sizeof helper_has_mem_fonction2(t) == sizeof(char))

int main()
{
foo* pf = 0;
bar* pb = 0;
toto* pt = 0;

#if 1 /////////////////////////////////////////
std::cout << std::boolalpha
<< HAS_static_fonction1(*pf) << ' '
<< HAS_static_fonction1(*pb) << ' '
#ifndef __GNUC__
<< HAS_static_fonction1(*pt) << ' '
<< HAS_static_fonction1(0) << ' '
#endif // __GNUC__
<< HAS_mem_fonction2(*pf) << ' '
<< HAS_mem_fonction2(*pb) << ' '
#ifndef __GNUC__
<< HAS_mem_fonction2(*pt) << ' '
<< HAS_mem_fonction2(0)
#endif // __GNUC__
<< 'n';

#else /////////////////////////////////////////
char a[HAS_static_fonction1(*pf)]; // Line 58 (OK)
char b[HAS_static_fonction1(*pb)]; // Line 59 (Error)
char c[HAS_static_fonction1(*pt)]; // Line 60 (Error)
char d[HAS_static_fonction1(0)]; // Line 61 (Error)
char e[HAS_mem_fonction2(*pf)]; // Line 62 (OK)
char f[HAS_mem_fonction2(*pb)]; // Line 63 (Error)
char g[HAS_mem_fonction2(*pt)]; // Line 64 (Error)
char h[HAS_mem_fonction2(0)]; // Line 65 (Error)

#endif /////////////////////////////////////////
return 0;
}
_________________________________________________________________

Cela compile et fonctionne correctement avec le compilo Comeau
en ligne <http://www.comeaucomputing.com/tryitout/> - bien que
cela ne permet pas d'exécuter le code généré, on peut vérifier
que HAS_static_fonction1() et HAS_mem_fonction2() renvoient
'true' et 'false' comme attendu en changeant le '#if 1' en
'#if 0'. On obtient des erreurs de compilation dans les lignes
59, 60, 61, 63, 64, 65 car la taille des tableaux définis dans
ces lignes vaut 0 (les lignes 58 et 62 passent).
L'intérêt des résultats 'bool' fournis par HAS_static_fonction1()
et HAS_mem_fonction2() est que ce sont des constantes de compilation,
qui permettent donc de spécialiser des templates en fonction de
la présence ou absence d'une fonction membre dans une classe.

Avec le gcc dont je dispose (version 3.3.3 sous CygWin), le
résultat est malheureusement moins brillant ; les lignes
comprises entre '#ifndef __GNUC__' ci dessus font des erreurs
de compilation si on devalide ce symbole de préprocesseur
(genre : "`fonctionX' is not a member of type `toto'" et
"`int' is not an aggregate type"), mais curieusement ça
passe pour la 'struct bar' (Affichage : "true false true false ").

Il serait intéressant de savoir comment se comportent des
gcc plus récents.

En revanche, je ne sais pas si cette technique pourrait être
étendue pour tester la présence des fonctions "libres"...

Falk

Avatar
Aurélien REGAT-BARREL
existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??


Comment peut-on arriver à une telle situation ? Il doit bien y avoir un
include quelque part non ? Cet include doit bien avoir un #define à tester
non ?

--
Aurélien REGAT-BARREL

Avatar
Alain Cabiran
existe-il un moyen de tester l'existence d'une fonction
à l'exécution ??



Comment peut-on arriver à une telle situation ? Il doit bien y avoir un
include quelque part non ? Cet include doit bien avoir un #define à tester
non ?



je devrais dormir un peu de temps en temps, ça me permettrait d'éviter
d'écrire des bêtises :-)

effectivement c'est bien à la compilation que je cherche à détecter
l'existence d'un "token" fonction, mot clef, ...

exemples simples : std::boolalpha, and, or, ...

n'existent pas dans g++ 2.95.

plus j'avance dans le bouquin de stroustrup et moins mon compilo
fonctionne :-) (j'exagère volontairement un peu).

le fait que j'utilise ce compilo sort du cadre de ce groupe et serait
plus vers celui de fr.comps.os.linux.

et non, les en-tête de gnu ne définissent pas l'existence ou pas
des manquants par rapport au c++ standard.

Alain Cabiran


Avatar
Luc Hermitte
Alain Cabiran wrote in
news:4176b349$0$15753$:

[...] n'existent pas dans g++ 2.95.

plus j'avance dans le bouquin de stroustrup et moins mon compilo
fonctionne :-) (j'exagère volontairement un peu).

le fait que j'utilise ce compilo sort du cadre de ce groupe et serait
plus vers celui de fr.comps.os.linux.


Nope. Pas vraiment. Comment un compilo supporte le standard est
parfaitement en thème.
Et puis, j'utilise GCC sous Widows XP. Quel rapport avec linux ?

et non, les en-tête de gnu ne définissent pas l'existence ou pas
des manquants par rapport au c++ standard.


Tu peux isoler les trucs qui changent et passer par une phase d'autotools
ou trucs similaires. Ou utiliserdes bibliothèques qui ont déjà
conaissaince des écarts et permettent de les ignorer.

Sinon, mettre à jour ton compilo est une bonne option ... Du chemin et
des années ont passé depuis les versions 2.95.

--
Luc Hermitte <hermitte at free.fr>
FAQ de <news:fr.comp.lang.c++> :
<http://www.cmla.ens-cachan.fr/Utilisateurs/dosreis/C++/FAQ/>
Dejanews : <http://groups.google.com/advanced_group_search>

Avatar
Aurelien REGAT-BARREL
et non, les en-tête de gnu ne définissent pas l'existence ou pas
des manquants par rapport au c++ standard.


Ben c'est pas le but des makefile et tout et tout ? Ils génèrent des petits
fichiers de test qu'ils tentent de compiler, en fonction du résultat ils
filent un #define via la ligne de commande ou génèrent un fichier genre
config.h qui te permet de savoir ce qui va / ce qui va pas...

--
Aurélien REGAT-BARREL>

Avatar
Alain Cabiran
Alain Cabiran wrote in
news:4176b349$0$15753$:


[...] n'existent pas dans g++ 2.95.

plus j'avance dans le bouquin de stroustrup et moins mon compilo
fonctionne :-) (j'exagère volontairement un peu).

le fait que j'utilise ce compilo sort du cadre de ce groupe et serait
plus vers celui de fr.comps.os.linux.



Nope. Pas vraiment. Comment un compilo supporte le standard est
parfaitement en thème.
Et puis, j'utilise GCC sous Widows XP. Quel rapport avec linux ?


et non, les en-tête de gnu ne définissent pas l'existence ou pas
des manquants par rapport au c++ standard.



Tu peux isoler les trucs qui changent et passer par une phase d'autotools
ou trucs similaires. Ou utiliserdes bibliothèques qui ont déjà
conaissaince des écarts et permettent de les ignorer.

Sinon, mettre à jour ton compilo est une bonne option ... Du chemin et
des années ont passé depuis les versions 2.95.



gcc sous cygwin est en version 3.3.4 si mes souvenirs sont bons.

Sous debian-toujours-a-la-bourre c'est 2.95 :-). Étant sous woody, Je ne
sais pas si je peux passer en testing sans risque : la woody d'install
ne reconnait pas ma carte scsi donc si ça crashe c'est l'enfer assuré
pour récupérer mon système.

voilà pourquoi j'utilise encore gcc 2.95

tant pis, le plus simple est de continuer comme ça, en espérant que la
sarge devienne rapidement stable. Je vais pas me faire un autotoconf
/ automake (que je ne connais pas de surcroit) pour chaque prog de 100
lignes...

pas grave, merci à toi et à tous pour vos réponses.

Alain


Avatar
Jean-Marc Bourguet
Alain Cabiran writes:

Sous debian-toujours-a-la-bourre c'est 2.95 :-). Étant sous woody, Je ne
sais pas si je peux passer en testing sans risque : la woody d'install
ne reconnait pas ma carte scsi donc si ça crashe c'est l'enfer assuré
pour récupérer mon système.


Il y a la 3.0.4 dans Debian Woody. Puis installer gcc
soi-même n'est pas très compliqué.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

1 2