在 Fortran 中,我需要派生类型中的过程指针,该指针可以指向多个子例程之一。这个问题在 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.
UPDATE
这是一个小修改,可以为编译器提供更多信息,但我还没有在大代码上尝试过这个。然而,这似乎是武断的,我不知道这是否有帮助。
...
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的新特性, the 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
任何帮助是极大的赞赏。