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 )