2017-06-19 2 views
0

Je cherche une manière élégante d'éviter de réécrire une fonction, dont l'implémentation est presque la même, mais seule la signature (le nombre de paramètres d'entrée et leurs types de données) est différente. Je sais que la surcharge de fonctions n'est pas possible en C. Je connais aussi l'existence de fonctions variadiques. Mais je pense qu'ils ne seront pas utiles dans cette situation.Alternatives à la surcharge de fonctions en C

Considérons le problème suivant, où nous devons calculer l'aire d'un triangle. Nous avons deux fonctions implémentant deux formules différentes: S = 1/2bh et S = sqrt (s (s-a) (s-b) (s-c)). En plus de calculer la surface, chacune des fonctions modifie également un paramètre nb ou nthr. Enfin, il existe une routine de niveau supérieur bisect_area_... qui lance une procédure de bissection sur une fonction donnée area_tria1 ou area_tria2 en l'optimisant pour un paramètre nb ou nthr. Actuellement, j'implémente explicitement deux fonctions de bissection: une pour la signature de area_tria1 et une autre pour area_tria2. Je pense qu'il doit y avoir une meilleure façon, plus élégante, qui permettrait d'avoir une seule fonction de bissection générique bisect_area_tria(). S'il vous plaît noter, dans le cas réel, que j'ai à portée de main, les types de données de paramètres d'entrée diffèrent également.

Voici un squelette pseudocode des signatures de fonction:

// Calculate area of triangle, modify and return parameter 'nb' 
void area_tria1_nb(..., int *nb, double b, double h, double *S) { 

    // change parameter 'nb' 
    ... 

    S = 0.5*b*h; 
} 

// Calculate area of triangle, modify and return parameter 'nthr' 
void area_tria1_nthr(..., int *nthr, double b, double h, double *S) { 

    // change parameter 'nthr' 
    ... 

    S = 0.5*b*h; 
} 

// Optimise calculation of area of triangle, for parameter 'nb' or 'nthr' 
void bisect_area_tria1(..., double b, double h, double *S, int (*area_tria1)(double, double)) { 
} 

// Calculate area of triangle, modify and return parameter 'nb' 
void area_tria2_nb(..., int *nb, double a, double b, double c, double *S) { 

    // change parameter 'nb' 
    ... 

    S = sqrt(s*(s-a)*(s-b)*(s-c)); 
} 


// Calculate area of triangle, modify and return parameter 'nthr' 
void area_tria_2_nthr(..., int *nthr, double a, double b, double c, double *S) { 

    // change parameter 'nthr' 
    ... 

    S = sqrt(s*(s-a)*(s-b)*(s-c)); 
} 


// Optimise calculation of area of triangle, for parameter 'nb' or 'nthr' 
void bisect_area_tria2(..., double a, double b, double c, double *S, int (*area_tria2)(double, double, double)) { 
} 

void main() { 

    bisect_area_tria1(..., &nb, b, h, &S, area_tria1_nb); 
    bisect_area_tria1(..., &nthr, b, h, &S, area_tria1_nthr); 

    bisect_area_tria2(..., &nb, a, b, c, &S, area_tria2_nb); 
    bisect_area_tria2(..., &nthr, a, b, c, &S, area_tria2_nthr); 

} 
+2

"Eviter la duplication de code" et "la surcharge de fonctions" ont peu à voir l'un avec l'autre. –

+2

'void area_tria1_nb (..., int * nb, double b, double h, double * S)' Assurez-vous que ce n'est pas un prototype valide. –

+1

Comme une sorte de commentaire vague ...Peut-être que le polymorphisme vous permettra d'utiliser une seule fonction pour effectuer les différents comportements que vous voulez. – byxor

Répondre

1

Ce que nous pouvons exploiter en utilisant des concepts de tableau.

1) Faire passer tous les arguments (valeurs), soit le double des constantes sous forme de tableaux, comme celui-ci

double arr[]={a,b,c,h}; 
int trial_no; //1 or 2 
bisect_area_tria2(..., &nthr,arr, &S, area_tria2_nthr,trial_no); 

Il en ce tableau d'utilisation de la fonction de référence comme ceci:

void area_tria2_nb(..., int *nb, double arr[], double *S,int trial_no) { 

    // change parameter 'nb' 
    ... 
if(trial_no==2){ 
    S = sqrt(s*(s-arr[0])*(s-arr[1])*(s-arr[2])); 
} 
else 
     S = 0.5*arr[1]*arr[3]; 
} 

Pour 'nb' ou 'nthr', il suffit de passer l'adresse de la variable correspondante. Ceci est juste la référence, peut ne pas être exacte pour votre situation. En cas de doute, demandez à nouveau.

+0

Oui, c'est une option à laquelle j'ai pensé: passer tous les arguments dans une structure de données ou un tableau de paramètres. – mabalenk

4

La façon naïve, simple de le faire:

#include <stdio.h> 

void func_int (int x) { printf("%d\n", x); } 
void func_char (char ch) { printf("%c\n", ch); } 

#define func(param)   \ 
    _Generic((param),   \ 
    int: func_int(param), \ 
    char: func_char(param)); \ 

int main() 
{ 
    func(1); 
    func((char){'A'}); 
} 

C'est le type sûr, mais prend en charge un seul paramètre. En un coup d'œil, cela peut sembler insuffisant.

Si vous voulez des listes de paramètres complètement variables, alors vous devrez implémenter un moyen d'analyser les macros variées et __VA_ARGS__. Probable, c'est possible. Probablement c'est moche. Probablement, ce n'est pas ce dont vous avez besoin.

Le besoin de surcharger les fonctions en général pourrait être «un problème XY». Vous devez avoir des fonctions avec différents jeux de paramètres et vous êtes convaincu que la surcharge de fonctions est la meilleure façon de le résoudre. Par conséquent, vous demandez comment faire une surcharge de fonction en C. Ce qui n'est pas nécessairement le meilleur moyen.

Un bien meilleur moyen serait de faire une interface de fonction avec un seul paramètre struct, qui peut être adapté pour contenir tous les paramètres nécessaires. Avec une telle interface, vous pouvez utiliser la méthode simple ci-dessus basée sur _Generic. Type sûr et maintenable.