如何在Fortran中将子程序名称作为参数传递?

7
传递子程序名称作为参数的语法是什么?示例:
  .
  .
call action ( mySubX ( argA, argB ) )
  .
  .

subroutine action ( whichSub ( argA, argB ) )
  ...
call subroutine whichSub ( argA, argB )
  ...
end subroutine action

目标是让 call subroutine whichSub ( argA, argB ) 的作用等同于 call subroutine mySubX ( argA, argB )。 我更喜欢避免传递开关参数,然后使用 SELECT CASE。

Fortran 的哪个版本和类型? - wallyk
2个回答

15

它是

call action(mySubX)

提供的操作看起来像

subroutine action(sub)
  !either - not recommmended, it is old FORTRAN77 style
  external sub
  !or - recommended
  interface
    subroutine sub(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface
  ! NOT BOTH!!

  call sub(argA, argB)

提供action知道将argA,argB放在哪里以代表aA,aB

否则,如果您还想传递参数

call action(mySubX, argA, argB)

subroutine action(sub, argA, argB)
  !either - not recommmended, it is old FORTRAN77 style
  external sub
  !or - recommended
  interface
    subroutine sub(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface

  integer, intent(...) :: argA, argB

  call sub(argA, argB)

我认为在这里使用函数指针并不好,当你有时需要更改指针的值(它所指向的子程序)时,它们很有用。在FORTRAN77中,普通过程参数可行,现在仍然适用。


因此,根据评论的要求,如果您在模块和具有正确接口的过程中,并且可以从模块访问该过程(可能在同一模块中),则可以使用过程语句来摆脱接口块:

module subs_mod
contains
  subroutine example_sub(aA, aB)
    integer,intent(...) :: aA, aB
    !the real example code
  end subroutine
end module

module action_mod
contains

  subroutine action(sub)
    use subs_mod
    procedure(example_sub) :: sub

    call sub(argA, argB)
  end subroutine
end module

但更有可能的是,你不会创建一个真正的子程序,而是创建一个抽象接口,并将其用过程语句引用,因此最终一切都与之前类似:

module action_mod

  abstract interface
    subroutine sub_interface(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface

contains

  subroutine action(sub)
    procedure(sub_interface) :: sub

    call sub(argA, argB)
  end subroutine
end module

很棒的解释。感谢您关于现代语言和函数指针使用方面的技巧。我们可以使用模块来避免接口吗? - dantopa
如果某个模块中有可用的兼容过程,您可以使用 procedure(mySubX) :: sub。您还可以在模块中拥有一个抽象接口,并使用相同的 procedure(nameOfTheInterface) - Vladimir F Героям слава
也许我错了,但我有这样的印象,即 external 关键字仅在调用者(使用过程参数调用的函数)中是必需的,而不是被调用者。否则,根据 12.4.2(Fortran 2008),它具有隐式接口。在 5.3.9#2 中:“如果将外部过程或虚拟过程用作实际参数或是过程指针的目标,则必须声明其具有 EXTERNAL 属性。” 它只在特殊情况下(基本上是接口使用 F90+ 功能)中对被调用者强制执行。 - user10307643
然而,我同意在这种情况下使用抽象接口和模块会更好。 - user10307643

2

我认为在现代Fortran编程中,使用模块来避免使用interface是一种好的实践,因为它可以提供更清晰的接口。

以下是实现这一理想的方法:

模块部分:

module foo
contains

subroutine callsub(sub,arg1,arg2)
!This subroutine is used to call other subroutines
external::sub !Use external to tell compiler this is indeed a subroutine
call sub(arg1,arg2)
end subroutine

subroutine sub(arg1,arg2)
!The subroutine to be called.
!do something
end sub

end module

以下是主程序:

program main
use foo !Use module automatically avoids using interface.
implicit none
!Declare about args
call callsub(sub,arg1,arg2)
end program

这里是我的演示,完整展示了如何实现这一点。


虽然这理论上回答了问题,但最好在此处包含答案的关键部分,并提供参考链接。 - Stephen Rauch
谢谢你的纠正。我是一个新手,还在学习礼仪。我添加了更多与问题相关的具体内容。 - Kiyomine
干得好,这是一个更好的答案,欢迎来到Stackoverflow! - Stephen Rauch
2
好的,这个设计确实消除了接口块的需要,但是子程序传递的重点在于你可以传递任何子程序。现在你在主程序中有了对sub的显式接口,但在callsub中没有。在现代Fortran中,使用procedure(sub)而不是external会更好。然后你可以在模块中只有一个抽象接口而不是整个sub。然后你意识到你又回到了一个接口块... - Vladimir F Героям слава

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接