Existe-t-il un moyen d'obtenir une surcharge de fonctions en C? Je regarde des fonctions simples à surcharger comme
foo (int a)
foo (char b)
foo (float c , int d)
Je pense qu'il n'y a pas de solution simple; Je recherche des solutions de contournement s'il en existe.
c
overloading
FL4SOF
la source
la source
Réponses:
Il y a peu de possibilités:
la source
Oui!
Depuis que cette question a été posée, le standard C (pas d'extensions) a effectivement pris en charge la surcharge de fonctions (pas les opérateurs), grâce à l'ajout du
_Generic
mot - clé dans C11. (pris en charge dans GCC depuis la version 4.9)(La surcharge n'est pas vraiment «intégrée» de la manière indiquée dans la question, mais il est très facile d'implémenter quelque chose qui fonctionne comme ça.)
_Generic
est un opérateur de compilation dans la même famille quesizeof
et_Alignof
. Il est décrit dans la section standard 6.5.1.1. Il accepte deux paramètres principaux: une expression (qui ne sera pas évaluée au moment de l'exécution) et une liste d'association type / expression qui ressemble un peu à unswitch
bloc._Generic
obtient le type global de l'expression puis "bascule" dessus pour sélectionner l'expression de résultat final dans la liste pour son type:L'expression ci-dessus est évaluée à
2
- le type de l'expression de contrôle estint
, elle choisit donc l'expression associée àint
comme valeur. Rien de tout cela ne reste à l'exécution. (Ladefault
clause est facultative: si vous la laissez désactivée et que le type ne correspond pas, cela provoquera une erreur de compilation.)La façon dont cela est utile pour la surcharge de fonctions est qu'il peut être inséré par le préprocesseur C et choisir une expression de résultat en fonction du type des arguments passés à la macro de contrôle. Donc (exemple de la norme C):
Cette macro implémente une
cbrt
opération surchargée , en distribuant le type de l'argument à la macro, en choisissant une fonction d'implémentation appropriée, puis en passant l'argument de macro d'origine à cette fonction.Donc, pour implémenter votre exemple d'origine, nous pourrions faire ceci:
Dans ce cas, nous aurions pu utiliser une
default:
association pour le troisième cas, mais cela ne montre pas comment étendre le principe à plusieurs arguments. Le résultat final est que vous pouvez utiliserfoo(...)
dans votre code sans vous soucier (beaucoup [1]) du type de ses arguments.Pour les situations plus compliquées, par exemple les fonctions surchargeant un plus grand nombre d'arguments ou des nombres variables, vous pouvez utiliser des macros utilitaires pour générer automatiquement des structures de répartition statiques:
( implémentation ici ) Donc, avec un peu d'effort, vous pouvez réduire la quantité de passe-partout pour ressembler à peu près à une langue avec un support natif pour la surcharge.
Soit dit en passant, il était déjà possible de surcharger le nombre d'arguments (pas le type) en C99.
[1] notez cependant que la façon dont C évalue les types peut vous tromper. Cela va choisir
foo_int
si vous essayez de lui passer un littéral de caractère, par exemple, et vous devez vous soucier un peu si vous voulez que vos surcharges prennent en charge les littéraux de chaîne. Dans l'ensemble, c'est plutôt cool.la source
Comme déjà indiqué, la surcharge dans le sens où vous voulez dire n'est pas prise en charge par C. Un idiome courant pour résoudre le problème est de faire accepter à la fonction une union étiquetée . Ceci est implémenté par un
struct
paramètre, oùstruct
lui - même se compose d'une sorte d'indicateur de type, comme unenum
, et d'ununion
des différents types de valeurs. Exemple:la source
whatever
s en fonctions séparées (set_int
,set_float
, etc.). Ensuite, "baliser avec le type" devient "ajouter le nom du type au nom de la fonction". La version de cette réponse implique plus de frappe, plus de coûts d'exécution, plus de risques d'erreurs qui ne seront pas détectées au moment de la compilation ... Je ne vois aucun avantage à faire les choses de cette façon! 16 votes positifs?!Voici l'exemple le plus clair et le plus concis que j'ai trouvé démontrant la surcharge de fonctions en C:
https://gist.github.com/barosl/e0af4a92b2b8cabd05a7
la source
Si votre compilateur est gcc et que cela ne vous dérange pas de faire des mises à jour à la main chaque fois que vous ajoutez une nouvelle surcharge, vous pouvez faire de la magie de macro et obtenir le résultat que vous voulez en termes d'appels, ce n'est pas aussi agréable à écrire ... mais c'est possible
regardez __builtin_types_compatible_p, puis utilisez-le pour définir une macro qui fait quelque chose comme
mais oui méchant, ne le faites pas
EDIT: C1X obtiendra un support pour les expressions génériques de type, elles ressemblent à ceci:
la source
Oui, en quelque sorte.
Voici l'exemple:
Il affichera 0 et bonjour .. à partir de printA et printB.
la source
L'approche suivante est similaire à celle de a2800276 , mais avec un peu de magie de macro C99 ajoutée:
la source
Cela peut ne pas aider du tout, mais si vous utilisez clang, vous pouvez utiliser l'attribut surchargeable - Cela fonctionne même lors de la compilation en C
http://clang.llvm.org/docs/AttributeReference.html#overloadable
Entête
la mise en oeuvre
la source
Dans le sens que vous voulez dire - non, vous ne pouvez pas.
Vous pouvez déclarer une
va_arg
fonction commevoid my_func(char* format, ...);
, mais vous devrez transmettre une sorte d'informations sur le nombre de variables et leurs types dans le premier argument - comme le
printf()
fait le fait.la source
Normalement, une verrue pour indiquer le type est ajoutée ou ajoutée au nom. Vous pouvez vous en tirer avec les macros dans certains cas, mais cela dépend plutôt de ce que vous essayez de faire. Il n'y a pas de polymorphisme en C, seulement de la coercition.
Des opérations génériques simples peuvent être effectuées avec des macros:
Si votre compilateur prend en charge typeof , des opérations plus compliquées peuvent être placées dans la macro. Vous pouvez alors avoir le symbole foo (x) pour prendre en charge la même opération de différents types, mais vous ne pouvez pas faire varier le comportement entre différentes surcharges. Si vous voulez des fonctions réelles plutôt que des macros, vous pourrez peut-être coller le type au nom et utiliser un second collage pour y accéder (je n'ai pas essayé).
la source
La réponse de Leushenko est vraiment cool - uniquement: l'
foo
exemple ne compile pas avec GCC, qui échouefoo(7)
, trébuchant sur laFIRST
macro et l'appel de fonction réel ((_1, __VA_ARGS__)
, restant avec une virgule excédentaire. De plus, nous sommes en difficulté si nous voulons fournir des surcharges supplémentaires , tel quefoo(double)
.J'ai donc décidé d'élaborer un peu plus la réponse, notamment pour permettre une surcharge de vide (
foo(void)
- ce qui a causé pas mal de problèmes ...).L'idée est maintenant: Définissez plus d'un générique dans différentes macros et laissez sélectionner le bon en fonction du nombre d'arguments!
Le nombre d'arguments est assez facile, basé sur cette réponse :
C'est bien, nous résolvons l'un
SELECT_1
ou l' autreSELECT_2
(ou plusieurs arguments, si vous le souhaitez / en avez besoin), nous avons donc simplement besoin de définitions appropriées:OK, j'ai déjà ajouté la surcharge void - cependant, celle-ci n'est en fait pas couverte par la norme C, ce qui ne permet pas d'arguments variadiques vides, c'est-à-dire que nous comptons alors sur des extensions de compilateur !
Au tout début, un appel de macro vide (
foo()
) produit toujours un jeton, mais vide. Ainsi, la macro de comptage renvoie en fait 1 au lieu de 0 même lors d'un appel de macro vide. Nous pouvons "facilement" éliminer ce problème, si nous plaçons la virgule après__VA_ARGS__
conditionnellement , selon que la liste est vide ou non:Cela semblait facile, mais la
COMMA
macro est assez lourde; heureusement, le sujet est déjà traité dans un blog de Jens Gustedt (merci Jens). L'astuce de base est que les macros de fonction ne sont pas développées si elles ne sont pas suivies de parenthèses, pour plus d'explications, jetez un œil au blog de Jens ... Il suffit de modifier un peu les macros selon nos besoins (je vais utiliser des noms plus courts et moins d'arguments pour la brièveté).Et maintenant nous allons bien ...
Le code complet en un seul bloc:
la source
Ne pouvez-vous pas simplement utiliser C ++ et ne pas utiliser toutes les autres fonctionnalités C ++ sauf celle-ci?
S'il n'y a toujours pas de C strict, je recommanderais plutôt les fonctions variadiques .
la source
Essayez de déclarer ces fonctions comme
extern "C++"
si votre compilateur le prenait en charge, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspxla source
J'espère que le code ci-dessous vous aidera à comprendre la surcharge de fonctions
la source