В Фортране мне нужен указатель процедуры внутри производного типа, который может указывать на одну из нескольких подпрограмм. Эта проблема, по-видимому, обычна для SO:
Сохранение процедуры Fortran как свойства в производном типе
Перегрузка процедур с привязкой к типу в Fortran 2003
Общие процедуры с привязкой к типу и аргументами процедуры
Процедура с привязкой к типу в качестве аргументов
назвать несколько. Ответ на этот вопрос для функций очень хорошо представлен в первом справочнике.
Однако мне до сих пор неясна методология разработки такого кода в случае, если указатель процедуры с привязкой к типу указывает на подпрограмму. Сложность, похоже, заключается в том, что с тем, что возвращается, не связано никакого типа (поскольку на самом деле ничего не «возвращается»).
Я также хотел бы указать на нюанс, что, хотя простое решение может существовать в более позднем стандарте fortran (2003,2008), это решение может работать не на всех компиляторах, что может быть проблематичным в будущем. Так что меня интересуют решения, удобные для компиляторов.
У меня есть небольшой код (показанный ниже), который в настоящее время работает, но в моем большом коде я получаю внутреннюю ошибку компилятора (также показанную ниже) в файле, где я использую указатели процедур в производных типах. Мой вопрос: что я могу сделать с приведенным ниже кодом, чтобы
1) Строго используйте явные интерфейсы
2) Максимизируйте информацию, передаваемую компилятору
3) Убедитесь, что код переносится между как можно большим количеством компиляторов (т. Е. Используйте стандарты fortran 90/95).
В какой степени может быть выполнено вышеперечисленное (1 является наиболее важным)? Возможно ли удовлетворить всем этим критериям, указанным выше? Я знаю, что «удовлетворить всем этим критериям» - это субъективно, но я бы сказал, что ответ «да» на тот же вопрос, касающийся функций, а не подпрограмм.
gcc version 5.1.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)
Небольшой код:
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
Ошибка компилятора в большом коде:
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.
ОБНОВЛЕНИЕ
Вот небольшая модификация, которая дает компилятору больше информации, но я не пробовал это на большом коде. Однако это кажется произвольным, и я понятия не имею, поможет это или нет.
...
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
КОММЕНТАРИИ К РЕШЕНИЮ Просто чтобы прокомментировать решение (предоставленное @IanH): была одна дополнительная проблема, а именно то, что у меня были некоторые производные типы, входящие в абстрактный интерфейс, что, согласно Новые возможности Fortran 2003, выражение Import
должно быть включено, чтобы сделать абстракцию интерфейс знает о любых вводимых производных типах. Вот небольшой рабочий пример, который, примененный к большому коду, смягчает внутреннюю ошибку компилятора, которую я имел :)
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
Любая помощь приветствуется.
-std=f95
в gfortran, и вы увидите, сколько вещей на самом деле Fortran 2003 и новее. - person Vladimir F   schedule 13.04.2016