Potrzebuję w podręczniku w języku Fortran wskaźnik proceduralny, który może wskazywać na jeden z wielu podprogramów. Problem ten wydaje się być powszechne na SO:Wskaźnik procedury Fortran do podprogramów w typach pochodnych
Fortran save procedure as property in derived type
Type bound procedure overloading in Fortran 2003
There is no matching specific subroutine for this type bound generic subroutine call
Generic type-bound procedures with procedure arguments
Type bound procedure as arguments
aby wymienić tylko kilka. Odpowiedź na to pytanie dla funkcji jest bardzo ładnie przedstawiona w pierwszym odnośniku.
Jednak nadal nie jestem pewien co do metodologii opracowania takiego kodu również w przypadku, gdy wskaźnik procedury związany z typem wskazuje na podprogram. Trudność wydaje się, że nie ma typu związanego z tym, co jest zwracane (ponieważ nic tak naprawdę nie jest "zwracane").
Chciałbym również podkreślić, że choć proste rozwiązanie może istnieć w nowszym standardzie fortuna (2003,2008), to rozwiązanie może nie działać na wszystkich kompilatorach, co może być problematyczne w przyszłości . Więc interesują mnie rozwiązania przyjazne dla kompilatorów.
Mam mały kod (pokazany poniżej), który obecnie działa, ale w moim dużym kodzie dostaję wewnętrzny błąd kompilatora (pokazany również poniżej) w pliku, w którym używam wskaźników procedur w typach pochodnych. Moje pytanie brzmi: co mogę zrobić, aby poniżej kod do
1) Ściśle używać jawnych interfejsy
2) Maksymalizacja informacje przekazywane do kompilatora
3) zapewnienia kod jest przenośny między tak wielu kompilatorów w miarę możliwości (tj. użyj fortranowych standardów 90/95).
W jakim stopniu powyższe może być spełnione (1 jest najważniejszy)? Czy powyższe kryteria są spełnione? Wiem, że to "spełnia wszystkie te kryteria" jest subiektywne, ale twierdzę, że odpowiedź brzmi "tak" dla tego samego pytania dotyczącego funkcji zamiast podprogramów.
gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)
Mała Kod:
module subs_mod
implicit none
public :: add,mult
contains
subroutine add(x,y,z)
implicit none
integer,intent(inout) :: x
integer,intent(in) :: y,z
x = y+z
end subroutine
subroutine mult(x,y,z)
implicit none
integer,intent(inout) :: x
integer,intent(in) :: y,z
x = y*z
end subroutine
end module
module type_A_mod
use subs_mod
implicit none
public :: type_A,init,operate
type type_A
procedure(),pointer,nopass :: op
end type
contains
subroutine init(A,op)
implicit none
external :: op
type(type_A),intent(inout) :: A
A%op => op
end subroutine
subroutine operate(A,x,y,z)
implicit none
type(type_A),intent(in) :: A
integer,intent(inout) :: x
integer,intent(in) :: y,z
call A%op(x,y,z)
end subroutine
end module
program test
use type_A_mod
use subs_mod
implicit none
type(type_A) :: A
integer :: x
call init(A,mult)
call operate(A,x,3,5)
write(*,*) 'x = ',x
end program
błąd kompilatora w dużym kodu:
f951.exe: internal compiler error: Segmentation fault
libbacktrace could not find executable to open
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://sourceforge.net/projects/mingw-w64> for instructions.
UPDATE
Oto mała modyfikacja, która daje kompilator więcej informacji, ale Nie próbowałem tego na wielkim kodzie. Wydaje się jednak arbitralne i nie mam pojęcia, czy to pomoże, czy nie.
...
function add(x,y,z) result(TF)
...
logical :: TF
x = y+z
TF = .true.
end function
function mult(x,y,z) result(TF)
...
logical :: TF
x = y*z
TF = .true.
end function
end module
module type_A_mod
...
type type_A
procedure(logical),pointer,nopass :: op
end type
...
subroutine init(A,op)
implicit none
logical,external :: op
...
end subroutine
subroutine operate(A,x,y,z)
...
logical :: TF
TF = A%op(x,y,z)
end subroutine
end module
program test
...
end program
ROZWIĄZANIE UWAGI tylko skomentować roztworu (dostarczonych przez @IanH) był jeden dodatkowy zmarszczek, a było to, że niektóre rodzaje otrzymane wprowadzania streszczenie interfejs, który według The New Features of Fortran 2003, należy dołączyć instrukcję Import
, aby abstrakcyjny interfejs był świadomy wszelkich wprowadzanych typów pochodnych. Oto mały przykład roboczych, które stosuje się do wielkiego kodu łagodzi wewnętrzny błąd kompilatora byłem mający :)
module DT_mod
implicit none
private
public :: DT
type DT
integer :: i
end type
contains
end module
module subs_mod
use DT_mod
implicit none
private
public :: add,mult,op_int
abstract interface
subroutine op_int(d,x,y,z)
import :: DT
implicit none
type(DT),intent(inout) :: d
integer,intent(inout) :: x
integer,intent(in) :: y,z
end subroutine
end interface
contains
subroutine add(d,x,y,z)
implicit none
type(DT),intent(inout) :: d
integer,intent(inout) :: x
integer,intent(in) :: y,z
x = y+z
d%i = 1
end subroutine
subroutine mult(d,x,y,z)
implicit none
type(DT),intent(inout) :: d
integer,intent(inout) :: x
integer,intent(in) :: y,z
x = y*z
d%i = 2
end subroutine
end module
module type_A_mod
use DT_mod
use subs_mod
implicit none
private
public :: type_A,init,operate
type type_A
procedure(op_int),pointer,nopass :: op
end type
contains
subroutine init(A,op)
implicit none
procedure(op_int) :: op
type(type_A),intent(inout) :: A
A%op => op
end subroutine
subroutine operate(A,d,x,y,z)
implicit none
type(DT),intent(inout) :: d
type(type_A),intent(in) :: A
integer,intent(inout) :: x
integer,intent(in) :: y,z
call A%op(d,x,y,z)
end subroutine
end module
program test
use type_A_mod
use subs_mod
use DT_mod
implicit none
type(type_A) :: A
type(DT) :: d
integer :: x,y,z
y = 3; z = 5
call init(A,mult)
call operate(A,d,x,y,z)
write(*,*) 'x,y,x = ',y,z,x
write(*,*) 'd%i = ',d%i
end program
Każda pomoc jest mile widziana.
Zastanów się, pokazując różnicę, trudno jest zobaczyć, co zmieniłeś w aktualizacji 2, szczególnie biorąc pod uwagę, że nie używasz żadnych pustych linii w kodzie (co utrudnia odczyt). –
BTW, spróbuj '-std = f95' w gfortran, a zobaczysz, ile rzeczy faktycznie jest Fortran 2003 i później. –
Dzięki @VladimirF, niedawno wypróbowałem to, to było pomocne. – Charlie