我正在使用过程重载和接口,以便在Fortran程序中实现某种通用性 为此,我有一个包含许多过程的模块,所有过程都是重复的,以便能够更改变量类型。我还在模块的开头有一系列类型的接口:
interface norm
module procedure &
norm_r8, &
norm_c
end interface
现在我的问题是我试图使用过程指针引用norm
,因此(在不同的模块中):
procedure(), POINTER :: pNorm => NULL()
pNorm => norm
然而,在这种情况下,gfortran给我一个错误,说我有一个未定义的引用规范。如果我指向norm_r8
或norm_c
,则没问题。但是由于分配指针的代码部分不知道调用norm时将使用的变量类型,我需要指向通用名称!有没有办法指出过载程序?
答案 0 :(得分:3)
据我所知,不允许过程指针指向通用接口。标准仅提及具有EXTERNAL属性的过程,模块过程或某些内部过程可与过程指针相关联(C1220,ISO / IEC 1539-1:2010)。 Gfortran还会为您的案例发出有用的错误消息:
Error: Procedure pointer target 'norm' at (1) must be either an intrinsic,
host or use associated, referenced or have the EXTERNAL attribute
有意义的是,您无法关联到界面,只能关联一个过程。接口仅在procedure(INTERFACE)
语句中使用,以提供它可以指向的过程的显式接口。
这不应该是一个showstopper,因为通用接口的目的可以否定你对指针的需求。只要指针用于所有可能的调用在类型,种类,等级和参数数量方面都是唯一的(因此编译器可以区分它们),您可以将它们全部添加到单个通用接口并在其中调用代替指针。或者,您可以使用select type()
构造有选择地将指针与类型的特定过程相关联,以避免需要与通用接口关联。
以下是基于参数类型
将指针指定给特定过程的包装程序示例subroutine get_proc_ptr(pp, arg)
implicit none
procedure(), pointer, intent(out) :: pp
class(*), intent(inout) :: arg
select type(arg)
type is (real(kind=kind(1d0)))
pp => norm_r8
type is (real)
pp => norm_r
type is (integer)
pp => norm_i
type is (complex)
pp => norm_c
class default
pp => null()
end select
end subroutine
可以使用这样的:
real(kind=kind(1d0)) :: arg_r8
procedure(), pointer :: pNorm => null()
arg_r8 = 4.0123456789d30
call get_proc_ptr(pNorm, arg_r8)
call pNorm(arg_r8)
这是一个完整的可编辑示例:
module proc
implicit none
interface norm
module procedure &
norm_r8, &
norm_r, &
norm_i, &
norm_c
end interface
contains
subroutine norm_r8(arg)
implicit none
real(kind=kind(1d0)), intent(in) :: arg
write (*,*) "real8: ", arg
end subroutine
subroutine norm_r(arg)
implicit none
real, intent(in) :: arg
write (*,*) "real: ", arg
end subroutine
subroutine norm_i(arg)
implicit none
integer, intent(in) :: arg
write (*,*) "integer: ", arg
end subroutine
subroutine norm_c(arg)
implicit none
complex, intent(in) :: arg
write (*,*) "complex: ", arg
end subroutine
subroutine get_proc_ptr(pp, arg)
implicit none
procedure(), pointer, intent(out) :: pp
class(*), intent(inout) :: arg
select type(arg)
type is (real(kind=kind(1d0)))
pp => norm_r8
type is (real)
pp => norm_r
type is (integer)
pp => norm_i
type is (complex)
pp => norm_c
class default
pp => null()
end select
end subroutine
end module
program test
use proc
implicit none
real(kind=kind(1d0)) :: arg_r8
real :: arg_r
integer :: arg_i
complex :: arg_c
procedure(), pointer :: pNorm => null()
arg_r8 = 4.0123456789d30
arg_r = 12.5
arg_i = 56
arg_c = (34,3)
call get_proc_ptr(pNorm, arg_r8)
call pNorm(arg_r8)
call get_proc_ptr(pNorm, arg_r)
call pNorm(arg_r)
call get_proc_ptr(pNorm, arg_i)
call pNorm(arg_i)
call get_proc_ptr(pNorm, arg_c)
call pNorm(arg_c)
end program
这是该程序的输出:
$ ./testprocptr
real8: 4.0123456788999999E+030
real: 12.5000000
integer: 56
complex: ( 34.0000000 , 3.00000000 )
答案 1 :(得分:0)
如果我理解得很好,你想一次完成两件事。 首先,您希望使用多态来让编译器调用正确的例程,具体取决于您是否具有不同的类型,等级,参数数量等。 其次,您希望使用过程指针在具有相同接口的不同过程之间切换。
我尝试过同样的事情。我没有设法指向一个接口,但我设法用指针创建一个接口。
如果您有这样的模块
module some_module
! This is the abstract interface for procedure pointers.
interface
subroutine shape_1_interface(arg)
implicit none
real, intent(in) :: arg
end subroutine shape_1_interface
subroutine shape_2_interface(arg)
implicit none
integer, intent(in) :: arg
end subroutine shape_2_interface
end interface
contains
subroutine routine_shape_1_implementation_1(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 1"
end subroutine routine_shape_1_implementation_1
subroutine routine_shape_2_implementation_1(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 1"
end subroutine routine_shape_2_implementation_1
subroutine routine_shape_1_implementation_2(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 2"
end subroutine routine_shape_1_implementation_2
subroutine routine_shape_2_implementation_2(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 2"
end subroutine routine_shape_2_implementation_2
subroutine routine_shape_1_implementation_3(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 3"
end subroutine routine_shape_1_implementation_3
subroutine routine_shape_2_implementation_3(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 3"
end subroutine routine_shape_2_implementation_3
end module some_module
然后你可以在你的主程序中做到:
program main
use some_module
implicit none
procedure(shape_1_interface), pointer :: routine_shape_1
procedure(shape_2_interface), pointer :: routine_shape_2
interface routine
procedure routine_shape_1
procedure routine_shape_2
end interface routine
routine_shape_1 => routine_shape_1_implementation_1
routine_shape_2 => routine_shape_2_implementation_1
call routine(4)
routine_shape_1 => routine_shape_1_implementation_2
routine_shape_2 => routine_shape_2_implementation_2
call routine(4.0)
end program main
遗憾的是,当您想要将指针设置为不同的实现时,您必须为所有形状执行此操作,但好处是您可以调用'routine'并自动获得所需的功能。
这是输出:
Arg is int 4
Implementation 1
Arg is real 4.00000000000000
Implementation 2