Fortran:将成员过程传递给外部函数
Fortran: Passing a member procedure to an external function
如何指向类型绑定过程?假设我有一些外部子例程,它接受一个指向只接受一个参数的函数的指针作为参数。
call integrator(f0)
如果函数 f0 在某处定义为看起来像
,这将起作用
function f0(x) result(val)
... do something...
end function
但现在我有一个带有一些类型绑定过程的 SomeClass 类型。这些类型绑定过程之一是
function integrand(this,x) result(val)
class(SomeClass), intent(in) :: this
...do something...
end function
我还有另一个相同类型的类型绑定过程,它想调用上面的子例程,将第一个类型绑定过程传递给它,但我不知道如何编写它!让我先试试有点幼稚的,
function CalculateIntegral(this) result(val)
class(SomeClass), intent(in) :: this
call integrator(this%integrand)
end function
这给了我
call integrator(this%integrand)
1
Error: Expected argument list at (1)
我从 this discussion 中学到的是因为 this%integrand 不是 return 指向函数的指针而是函数的绑定。
那么,现在我试试这个
function CalculateIntegral(this) result(val)
class(SomeClass), intent(in) :: this
call integrator(integrand)
end function
并且它编译但给我一个内存引用错误,因为它试图将值 (x) 传递给用于 class(SomeClass) 类型参数(即 this)的东西。
所以如果 this%integrand 只给我一个绑定而不是一个指向类型绑定成员过程的指针,我如何将我的一个类型绑定成员过程传递给外部子例程而不需要第一个 "this" 争论妨碍了?
注意:我习惯于在 python 中编码,其中 self.integrand 可以传递给外部函数,一切都会很好。
编辑:我的错;我记错了。如果您尝试将 self.integrand 传递给外部函数,Python 会出现同样的问题。
按照@Vladimir 评论中的链接,传递内部过程似乎适用于最近的编译器(注意:我认为第一个示例是以下代码中最简单和最好的):
module mymod
implicit none
type mytype
real :: q
contains
procedure :: calc_integral
end type
contains
function calc_integral( this, a, b ) result( ans )
class(mytype) :: this
real :: a, b, ans
call integrator( myfunc, a, b, ans )
contains
function myfunc( x ) result( val )
real :: x, val
val = this% q * x
end function
endfunction
end module
!! Some external library.
subroutine integrator( func, a, b, ans )
external :: func
real :: a, b, ans, func
ans = func( a ) + func( b )
end
program main
use mymod
type(mytype) :: mt
mt% q = 100.0
print *, mt% calc_integral( 1.0, 2.0 ) !! gives 300.0
end
在上面的代码中,也可以将模块过程传递给 integrator()
(而不是传递内部过程),但在那种情况下,this_
可能需要 [=] 16=] 访问类型组件(见下一个案例)。
下面是另一种以不同方式传递被积函数的尝试。
这里,指向模块过程 myfunc()
的指针被传递给 integrator()
module mymod
implicit none
interface
function integrand_i( x ) result( val )
real :: x, val
endfunction
endinterface
type mytype
real :: q
procedure(integrand_i), nopass, pointer :: integrand
contains
procedure :: init
endtype
class(mytype), pointer :: this_
contains
subroutine init( this )
class(mytype), target :: this
this% integrand => myfunc
this_ => this
endsubroutine
function myfunc( x ) result( val )
real :: x, val
val = this_ % q * x
endfunction
end module
! subroutine integrator() here
program main
use mymod
type(mytype) :: mt
real :: ans
call mt% init
mt% q = 100.0
call integrator( mt% integrand, 1.0, 2.0, ans )
print *, ans
end
这看起来有点类似于 OP 在问题中的原始方法(在我看来)。
另一种(无效的)方法是修改上面的 init()
以便它获得指向内部过程的指针
subroutine init( this )
class(mytype) :: this
this% integrand => myfunc
contains
function myfunc( x ) result( val )
real :: x, val
val = this % q * x
endfunction
endsubroutine
但这不起作用,因为退出 init() 时内部过程变得未定义。同样,以下似乎也不起作用(它甚至不能用 gfortran4.8.2 编译)。
type mytype
...
contains
procedure :: integrand
endtype
...
function integrand( this ) result( ptr )
class(mytype) :: this
procedure(integrand_i), pointer :: ptr
ptr => myfunc
contains
function myfunc( x ) result( val )
real :: x, val
val = this % q * x
endfunction
endfunction
program main
...
call integrator( mt% integrand, 1.0, 2.0, ans )
如何指向类型绑定过程?假设我有一些外部子例程,它接受一个指向只接受一个参数的函数的指针作为参数。
call integrator(f0)
如果函数 f0 在某处定义为看起来像
,这将起作用function f0(x) result(val)
... do something...
end function
但现在我有一个带有一些类型绑定过程的 SomeClass 类型。这些类型绑定过程之一是
function integrand(this,x) result(val)
class(SomeClass), intent(in) :: this
...do something...
end function
我还有另一个相同类型的类型绑定过程,它想调用上面的子例程,将第一个类型绑定过程传递给它,但我不知道如何编写它!让我先试试有点幼稚的,
function CalculateIntegral(this) result(val)
class(SomeClass), intent(in) :: this
call integrator(this%integrand)
end function
这给了我
call integrator(this%integrand)
1
Error: Expected argument list at (1)
我从 this discussion 中学到的是因为 this%integrand 不是 return 指向函数的指针而是函数的绑定。
那么,现在我试试这个
function CalculateIntegral(this) result(val)
class(SomeClass), intent(in) :: this
call integrator(integrand)
end function
并且它编译但给我一个内存引用错误,因为它试图将值 (x) 传递给用于 class(SomeClass) 类型参数(即 this)的东西。
所以如果 this%integrand 只给我一个绑定而不是一个指向类型绑定成员过程的指针,我如何将我的一个类型绑定成员过程传递给外部子例程而不需要第一个 "this" 争论妨碍了?
注意:我习惯于在 python 中编码,其中 self.integrand 可以传递给外部函数,一切都会很好。
编辑:我的错;我记错了。如果您尝试将 self.integrand 传递给外部函数,Python 会出现同样的问题。
按照@Vladimir 评论中的链接,传递内部过程似乎适用于最近的编译器(注意:我认为第一个示例是以下代码中最简单和最好的):
module mymod
implicit none
type mytype
real :: q
contains
procedure :: calc_integral
end type
contains
function calc_integral( this, a, b ) result( ans )
class(mytype) :: this
real :: a, b, ans
call integrator( myfunc, a, b, ans )
contains
function myfunc( x ) result( val )
real :: x, val
val = this% q * x
end function
endfunction
end module
!! Some external library.
subroutine integrator( func, a, b, ans )
external :: func
real :: a, b, ans, func
ans = func( a ) + func( b )
end
program main
use mymod
type(mytype) :: mt
mt% q = 100.0
print *, mt% calc_integral( 1.0, 2.0 ) !! gives 300.0
end
在上面的代码中,也可以将模块过程传递给 integrator()
(而不是传递内部过程),但在那种情况下,this_
可能需要 [=] 16=] 访问类型组件(见下一个案例)。
下面是另一种以不同方式传递被积函数的尝试。
这里,指向模块过程 myfunc()
的指针被传递给 integrator()
module mymod
implicit none
interface
function integrand_i( x ) result( val )
real :: x, val
endfunction
endinterface
type mytype
real :: q
procedure(integrand_i), nopass, pointer :: integrand
contains
procedure :: init
endtype
class(mytype), pointer :: this_
contains
subroutine init( this )
class(mytype), target :: this
this% integrand => myfunc
this_ => this
endsubroutine
function myfunc( x ) result( val )
real :: x, val
val = this_ % q * x
endfunction
end module
! subroutine integrator() here
program main
use mymod
type(mytype) :: mt
real :: ans
call mt% init
mt% q = 100.0
call integrator( mt% integrand, 1.0, 2.0, ans )
print *, ans
end
这看起来有点类似于 OP 在问题中的原始方法(在我看来)。
另一种(无效的)方法是修改上面的 init()
以便它获得指向内部过程的指针
subroutine init( this )
class(mytype) :: this
this% integrand => myfunc
contains
function myfunc( x ) result( val )
real :: x, val
val = this % q * x
endfunction
endsubroutine
但这不起作用,因为退出 init() 时内部过程变得未定义。同样,以下似乎也不起作用(它甚至不能用 gfortran4.8.2 编译)。
type mytype
...
contains
procedure :: integrand
endtype
...
function integrand( this ) result( ptr )
class(mytype) :: this
procedure(integrand_i), pointer :: ptr
ptr => myfunc
contains
function myfunc( x ) result( val )
real :: x, val
val = this % q * x
endfunction
endfunction
program main
...
call integrator( mt% integrand, 1.0, 2.0, ans )