【问题标题】:Fortran: Passing a member procedure to an external functionFortran:将成员过程传递给外部函数
【发布时间】:2015-07-27 04:04:52
【问题描述】:

如何指向类型绑定过程?假设我有一些外部子例程,它接受一个指向只接受一个参数的函数的指针作为参数。

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 不返回指向函数的指针,而是对函数的绑定。

所以,我现在试试这个

function CalculateIntegral(this) result(val)
 class(SomeClass), intent(in) :: this

 call integrator(integrand)
end function

它编译但给了我一个内存引用错误,因为它试图将值 (x) 传递给类 (SomeClass) 类型的参数(即 this)。

所以如果 this%integrand 只给我一个绑定而不是一个指向类型绑定成员过程的指针,我如何在没有第一个“this”参数进入的情况下将我的一个类型绑定成员过程传递给外部子例程怎么走?

注意:我习惯用 python 编码,其中 self.integrand 可以传递给外部函数,一切都会好起来的。

编辑:我的错;我记错了。如果您尝试将 self.integrand 传递给外部函数,Python 也会遇到同样的问题。

【问题讨论】:

  • 几乎是stackoverflow.com/questions/31208594/… 的副本,该解决方案也应适用于此处。您应该说明 Python 方法的确切含义,即使在 Python 中也有更多的回调方法。另见fortran90.org/src/best-practices.html#callbacks
  • @VladimirF 这个帖子会因为重复而关闭吗?如果尚未确定,我将在下面更新我的代码以征求意见或更好的方法。如果重复的可能性很高,我将删除下面的代码。)
  • 应该不会吧,不知道其他人怎么看,不过暂时不会关闭。也许如果在其他地方有一个真正完全相同的副本,但我的回答只是说明了更多的可能性之一。

标签: fortran


【解决方案1】:

按照@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()(而不是传递内部过程),但在这种情况下,myfunc() 可能需要类似this_ 来访问类型组件(见下一个案例)。

下面是另一种以不同方式传递被积函数的尝试。 这里,一个指向模块过程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 )

【讨论】:

  • 通过阅读弗拉基米尔评论中的链接,我尝试了几种方法,但除了第一种方法,我找不到如何从模块中删除“this_”指针...顺便说一句,如果时间允许,你能在问题的最后放一些简单的 Python 代码示例吗? (我还在学习 Python,所以想试试 :)
  • 请注意,Fortran 中没有“成员”函数这样的东西,因此“非成员”是没有意义的。第三种方法失败的原因是当宿主过程的实例完成时,指向内部过程的过程指针变得未定义。我看不出使用过程指针组件的意义。
  • 我已经相应地更新了答案。这是否意味着内部函数的生命周期与本地“自动”变量(粗略地说)基本相同?
  • @roygvib 是的,宿主函数不能退出,它必须还在堆栈上。 Fortran(或 C 和类似语言)中没有词法闭包。
  • @VladimirF 非常感谢。是的,我对类似的东西感兴趣(将嵌套或本地函数 + 它的环境作为“包”传递),但在这种情况下似乎无效。
猜你喜欢
  • 2019-09-27
  • 2014-08-20
  • 1970-01-01
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-09
  • 2013-01-13
相关资源
最近更新 更多