Oto typowe użycie wskaźników funkcji w C. Chciałbym zrobić coś podobnego w Fortranie. Mam kilka pomysłów, ale chciałbym wiedzieć, czy istnieje jakiś kanoniczny sposób.
Wskaźniki funkcji i konteksty przekazane przez użytkownika są przechowywane, a następnie wywoływane później.
typedef PetscErrorCode (*TSIFunction)(TS,PetscReal,Vec,Vec,Vec,void*);
PetscErrorCode TSSetIFunction(TS ts,Vec res,TSIFunction f,void *ctx);
Funkcja użytkownika jest wywoływana za pomocą kontekstu w późniejszym czasie.
W PETSc często wykorzystują tabele wskaźników string -> function. Wszystko jest wtyczką, więc użytkownik może zarejestrować własne implementacje i są one najwyższej klasy.
#define PCGAMG "gamg"
PCRegisterDynamic(PCGAMG ,path,"PCCreate_GAMG",PCCreate_GAMG);
To rejestruje procedurę tworzenia w „FList”, a następnie PCSetFromOptions () oferuje możliwość wyboru tej metody w porównaniu z innymi opcjami. Jeśli system obsługuje ładowanie dynamiczne, możesz pominąć zależność czasu kompilacji od symbolu PCCreate_GAMG i po prostu przekazać NULL, wówczas symbol zostanie wyszukany w udostępnionej bibliotece w czasie wykonywania.
Zauważ, że ten krok poza „fabryką” jest odwróceniem urządzenia sterującego podobnego do tego, co Martin Fowler nazywa „lokalizatorem usług”.
Uwaga: pojawiło się to w mojej prywatnej korespondencji z Jedem Brownem, gdzie zadał mi to pytanie. Postanowiłem to zlecić na zewnątrz i zobaczyć, jakie odpowiedzi ludzie mogą wymyślić.
Wydaje mi się, że w twoim pytaniu jest wiele języka specyficznego dla PETSc (z którym nie jestem zaznajomiony), więc może pojawić się zmarszczka, której nie do końca rozumiem, ale może nadal będzie to przydatne Rozpoczęty.
Zasadniczo musisz zdefiniować interfejs dla procedury, a następnie możesz przekazać wskaźnik do funkcji następującej po tym interfejsie. Poniższy kod pokazuje przykład. Po pierwsze, istnieje moduł, który definiuje interfejs i pokazuje szybki przykład fragmentu kodu, który wykonałby procedurę udostępnioną przez użytkownika korzystającego z tego interfejsu. Dalej jest program, który pokazuje, w jaki sposób użytkownik użyłby tego modułu i zdefiniował funkcję do wykonania.
źródło
PROCEDURE(function_template), POINTER :: func
wewnętrzne jest dość trywialne .void*
, użytkownik musi sam napisać interfejsy dla funkcji bibliotecznych. Jeśli zaimplementujesz bibliotekę w C, to wystarczy, ale jeśli zaimplementujesz w Fortran, musisz upewnić się, że kompilator nigdy nie zobaczy „fałszywego” INTERFEJSU biblioteki w tym samym czasie, co INTERFEJS użytkownika.void*
w Fortran jesttransfer
metoda. Zobacz tutaj przykład użycia. Pozostałe 3 podejścia oprócztransfer
metody to „tablice robocze”, „specyficzny typ pochodny zamiastvoid *
” i użycie zmiennych modułu lokalnych dla modułu.transfer
jakiś nonsensowny typ (character (len=1), allocatable
) tylko po to, by wywołać tę funkcję.