在 Fortran 中从外部 类 传递子例程名称
Passing subroutine names from external classes in Fortran
在 中,我们学习了如何在 Fortran classes 中将子例程名称作为参数传递。但是我们如何从外部传递子程序名称 class?
随后的代码为使用 GNU Fortran (GCC) 5.1.0 的两次不同尝试产生编译错误:
gfortran -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5 casey.f08
casey.f08:42:37:
call selector ( ints % square, x , y )
1
Error: Expected argument list at (1)
casey.f08:43:24:
call selector ( ints % double ( x, y ), x , y )
1
Error: ‘double’ at (1) should be a FUNCTION
例程 selector
的目标是采用不同的计算路径:一个计算一个数的平方,另一个计算它的两倍。第一个编译错误建议添加一个参数列表。对此的幼稚补救措施会产生第二个错误。
随后是 MWE。排列编程产生了许多变体;希望这个版本可以轻松修复。
module myModule
implicit none
type :: intermediates
real :: z
contains
private
procedure, nopass, public :: square => square_sub
procedure, nopass, public :: double => double_sub
end type intermediates
private :: square_sub
private :: double_sub
contains
subroutine square_sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x ** 2
end subroutine square_sub
subroutine double_sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x * 2
end subroutine double_sub
end module myModule
program casey
use myModule
implicit none
real :: x = 10.0, y
type ( intermediates ) :: ints
call selector ( ints % square, x , y )
call selector ( ints % double ( x, y ), x , y )
contains
subroutine selector ( sub, x, y )
interface mySub
subroutine sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
end subroutine sub
end interface mySub
real, intent ( in ) :: x
real, intent ( out ) :: y
call sub ( x, y )
print *, 'x = ', x, ', y = ', y
end subroutine selector
end program casey
解决方案是将选择器过程放在 class 中。在上面的示例中,subroutine selector
在 program
内。 subroutine local_selector
下面是 mySubs
.
类型的 procedure
module mySubs
implicit none
type :: myClass
contains
procedure, nopass, public :: square
procedure, nopass, public :: double
procedure, nopass, public :: local_selector
end type myClass
contains
subroutine square ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x ** 2
print *, 'x = ', x, '; x ** 2 = ', y
end subroutine square
subroutine double ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x * 2
print *, 'x = ', x, '; 2 x = ', y
end subroutine double
subroutine local_selector ( sub, x, y )
interface mySub
subroutine sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
end subroutine sub
end interface mySub
real, intent ( in ) :: x
real, intent ( out ) :: y
call sub ( x, y )
end subroutine local_selector
end module mySubs
program fixed
use mySubs
implicit none
real :: x = 10.0, y
type ( myClass ) :: thisClass
call thisClass % local_selector ( square, x , y )
call thisClass % local_selector ( double, x , y )
end program fixed
在
随后的代码为使用 GNU Fortran (GCC) 5.1.0 的两次不同尝试产生编译错误:
gfortran -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5 casey.f08
casey.f08:42:37:
call selector ( ints % square, x , y )
1
Error: Expected argument list at (1)
casey.f08:43:24:
call selector ( ints % double ( x, y ), x , y )
1
Error: ‘double’ at (1) should be a FUNCTION
例程 selector
的目标是采用不同的计算路径:一个计算一个数的平方,另一个计算它的两倍。第一个编译错误建议添加一个参数列表。对此的幼稚补救措施会产生第二个错误。
随后是 MWE。排列编程产生了许多变体;希望这个版本可以轻松修复。
module myModule
implicit none
type :: intermediates
real :: z
contains
private
procedure, nopass, public :: square => square_sub
procedure, nopass, public :: double => double_sub
end type intermediates
private :: square_sub
private :: double_sub
contains
subroutine square_sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x ** 2
end subroutine square_sub
subroutine double_sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x * 2
end subroutine double_sub
end module myModule
program casey
use myModule
implicit none
real :: x = 10.0, y
type ( intermediates ) :: ints
call selector ( ints % square, x , y )
call selector ( ints % double ( x, y ), x , y )
contains
subroutine selector ( sub, x, y )
interface mySub
subroutine sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
end subroutine sub
end interface mySub
real, intent ( in ) :: x
real, intent ( out ) :: y
call sub ( x, y )
print *, 'x = ', x, ', y = ', y
end subroutine selector
end program casey
解决方案是将选择器过程放在 class 中。在上面的示例中,subroutine selector
在 program
内。 subroutine local_selector
下面是 mySubs
.
procedure
module mySubs
implicit none
type :: myClass
contains
procedure, nopass, public :: square
procedure, nopass, public :: double
procedure, nopass, public :: local_selector
end type myClass
contains
subroutine square ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x ** 2
print *, 'x = ', x, '; x ** 2 = ', y
end subroutine square
subroutine double ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
y = x * 2
print *, 'x = ', x, '; 2 x = ', y
end subroutine double
subroutine local_selector ( sub, x, y )
interface mySub
subroutine sub ( x, y )
real, intent ( in ) :: x
real, intent ( out ) :: y
end subroutine sub
end interface mySub
real, intent ( in ) :: x
real, intent ( out ) :: y
call sub ( x, y )
end subroutine local_selector
end module mySubs
program fixed
use mySubs
implicit none
real :: x = 10.0, y
type ( myClass ) :: thisClass
call thisClass % local_selector ( square, x , y )
call thisClass % local_selector ( double, x , y )
end program fixed