Skrócenie kodu kilku funkcji do obliczeń matematycznych

0

Kiedyś już chyba pojawił się taki temat, jednak rozwiązanie w nim podane nie do końca spełnia moje potrzeby. Nie wiem, czy mój "problem" uda się rozwiązać, ale być może ktoś z Was wpadnie na jakiś pomysł. ;)

Ok, zaczynam. Mam kilka funkcji, które wykonują obliczenia matematyczne na pewnym buforze (z liczbami), funkcje wyglądają tak:

void funX(double *buf, int size)
{
     // trochę zmiennych
     double wynik;
     outter_lib_X key;

     wynik = call_fun_XX(buff, size, key);
    // operacje na wyniku i wyświetlenie go
}

void funY(double *buf, int size)
{
   // trochę zmiennych
     double wynik;
     outter_lib_Y key;

     wynik = call_fun_YY(buff, size, key);
    // operacje na wyniku i wyświetlenie go
}

void funZ(double *buf, int size)
{
   // trochę zmiennych
     double wynik;
     outter_lib_Z key;

     wynik = call_fun_ZZ(buff, size, key);
    // operacje na wyniku i wyświetlenie go
}

Wydaje się proste, ale są 2 kwestie:

  1. podfunkcje wywoływane w funkcjach mają różne nazwy - każda dla każdej funkcji jest inna
  2. podfunkcje mają właściwie takie same argumenty, różnią się jedynie typem danych zmiennej 'key' - w każdej funkcji jest ona innego typu (zdefiniowango w zewnętrzej bibioltece, której używam i nie mogę zmienić)

Jakieś pomysły, jak uprościć taki kod? Gdybym chciał dodać więcej funkcji robiących właściwie to samo, ale wywoływujących inną podfunkcję z innym kluczem, to kod mi się rozrasta, a czuję, ;) że da się to zrobić prościej.

0

Zależnie od tego co robią podfunkcje można to pewnie zrobić na szablonach ;) Ewentualnie jedna funkcja szablonowa przyjmująca wskaźnik do podfunkcji.

0

Z szablonami nie da rady bo to jest C :( podfunkcje też są z zewnętrznej biblioteki, więc nie mam możliwości ich zmiany

1

W samym C zabawa z typami jest mocno ograniczona, nie masz szablonów i nie można robić z nich fajnych typedefów (struktur typu 'traits').

#define DEF_FOO_FUNC(NAME) \
    void fun##NAME(double *buf, int size) \
    { \
        double wynik; \
        outer_lib_##NAME key; \
        wynik = call_fun_##NAME(buf, size, key); \
        operacje_na_wyniku(wynik); \
    }

I gdzieś niżej:

DEF_FOO_FUNC(X)
DEF_FOO_FUNC(Y)
DEF_FOO_FUNC(Z)
0

Hm, pomysł świetny, tylko teraz jeszcze raz patrzę na swój właściwy kod i ... raczej się nie uda. Oprócz tego mam w każdej funkcji głównej wywoływania innych podfunkcji, wiązanych z daną funkcją, ale kompletnie różnymi nazwami.

0

Pytanie, ile jest tych funkcji, i jak dużo kodu mają?
Bo jeśli rzeczywisty kod wygląda tak jak w przykładzie, to najlepiej będzie nic nie robić, i zostawić tak jak jest.

Jeśli jednak funkcji jest, dajmy na to, sto, lepiej byłoby mieć coś takiego

void fun(double *buf, int size, int kind)
{
}

gdzie ostatni parametr oznaczałby która funkcja ma się wykonać. wewnątrz możesz użyć switcha, ifów, tablicy wskaźników — wszystko zależy co będzie ładniej wyglądało.

0

A w C++ wyglądałoby to po prostu tak:

template <typename TKey, double (*TFunc)(double*, int, TKey)>
void fun(double *buf, int size)
{
    TKey key;
    double wynik = TFunc(buf, size, key);

    // coś z wynikiem
}

I później:

fun<outer_lib_X, call_fun_X>(costam, costam);
0

A nie można tego zrobić nieco prościej np. tak:

num Type = {X, Y, Z};

void funX(double *buf, int size, Type type)
{
     // trochę zmiennych
     double wynik;
     outter_lib_X key;
     switch(type)
     {
     case X:
     wynik = call_fun_XX(buff, size, key);
    // operacje na wyniku i wyświetlenie go
     break;
     case Y:
     //... j.w.
     }

}
0

na chwilę obecną funkcji jest 6, ale nie wykluczam dodania kolejnych, stąd takie moje myśli nt skrócenia kodu.

Zakładając, że będę miał swich/ify/else, kod właściwie będzie wyglądał podobnie jak teraz - więc chyba lepiej będzie to zostawić, jak jest, bo przynajmniej widać, co się w kodzie dzieje.

Możliwe to jest, że lepiej zostawić powtarzalny (poniekąd) kod, zamiast na siłę go skracać?

0

Ja wiem, ale całość powstaje w C, więc nie zmienię tego teraz na C++. Podam jeszcze jeden przykład:

void test_fun_X(){

    FUN_X_KEY keyX, keyY;
    char *key[100];
    
    if(FUN_X_set_key_1(key, len, &keyX) < 0)
    {
        exit(-1);
    }

    if(!warunek)
    {
        FUN_X_do_sth(tmp1, tmp2, len, &keyX, tmp3, 0);
        if (FUN_X_set_key_2(key, len, &keyY) < 0)
        {
            exit(-1);
        }
    }
    
    FUN_X_do_sth(buff1, buff2, len, &keyX, tmp3, 1);
}
void test_fun_Y(){

    FUN_Y_KEY keyX, keyY;
    char *key[100];
    
    if(FUN_Y_set_key_1(key, len, &keyX) < 0)
    {
        exit(-1);
    }

    if(!warunek)
    {
        FUN_Y_do_sth(tmp1, tmp2, len, &keyX, tmp3, 1);
        if (FUN_Y_set_key_2(key, len, &keyY) < 0)
        {
            exit(-1);
        }
    }
    
    FUN_Y_do_sth(buff1, buff2, len, &keyX, tmp3, 1);
}

I teraz tak. Podfunkcje, czyli FUN_Y_do_sth oraz FUN_X_do_sth mogą mieć różne nazwy, np:

FUN_Y_do2_sth, FUN_X_do2_sth itd .. Rzecz w tym, że jeśli chcę dodać nową funkcję, np. test_fun_K, to muszę właściwie kopiować podany kod i zmieniać tylko nazwy podfunkcji (czasem niektóe parametry, np. rozmiary tablic) które są argumentami funkcji.

Nie wiem tylko, czy zbytnim skróceniem kodu nie otrzymam kodu mniej czytelnego.

0

Dlaczego switch w 95% przypadków nie jest dobrym pomysłem?

0

Gdyby nie różne outter_lib (cokolwiek to jest) to można byłoby zrobić tak:

void funXYZ(double *buf, int size, double (*funXYZ)(double*, int, outter_lib))
{
     // trochę zmiennych
     double wynik;
     outter_lib_X key;
 
     wynik = funXYZ(buff, size, key);
    // operacje na wyniku i wyświetlenie go
}
0

Wiem wiem, ale ja piszę w samym C i nie chcę mieszać ;)

0

Ale czego mieszać?
Wskaźniki do funkcji są chyba również w czystym C...

0

Bo 100 linijek switcha da sie zastapic jedna linijka mapy.

@n0name_l O jakiej mapie mówisz? Sorry, ale nigdy o czymś takim nie słyszałem - programuję tylko hobbystycznie więc proszę o wyrozumiałość. Jeśli jest taka możliwość to poproszę o krótki przykład wykorzystania "mapy" i switch dla porównania.

1 użytkowników online, w tym zalogowanych: 0, gości: 1