Fortran中的程序指针 [英] Procedural pointer in fortran

查看:13
本文介绍了Fortran中的程序指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下指向单参数的双精度函数的抽象接口

module abstract

  abstract interface
     function dp_func (x)
       double precision, intent(in) :: x
       double precision :: dp_func
     end function dp_func
  end interface

end module abstract

在不同的模块中,我定义了两个函数,一个简单的g类型dp_func和一个更复杂的f

module fns

 contains
 double precision function f(a,b,x)
   double precision, intent(in)::a,b,x
   f=(a-b)*x 
 end function f

 double precision function g(x)
   double precision, intent(in)::x
   g=x**2 
 end function g
end module fns

现在可以创建指向g的指针,如下所示

program main
use abstract,fns
procedure(dp_func), pointer :: p
double precision::x=1.0D0, myA=1.D2, myB=1.D1, y
p => g
y=p(x)
end program main
但如何创建指向f(myA,myB,x)的指针,即指向ab的固定值的f的指针,这可以被视为只有一个参数的函数,即dp_func类型? 最终,我希望能够编写类似

的内容
p=>f(myA, myB, )
y=p(x)

下面的注释表明function closure不是Fortran标准的一部分,包装函数可能是它的解决方案。但是,包装器必须初始化,这会导致最终用户可能忘记调用初始化式。如何才能以干净透明的方式做到这一点?

编辑 在发布这个问题并用谷歌搜索";闭包和Fortran";之后,我找到了这个例子

我以图片的形式呈现,以强调突出。这是在一门在线课程中介绍的。但我怀疑这种隐式参数设置是否是良好的编程实践。事实上,像本例中的z这样的悬空变量就是错误的完美来源!

推荐答案

您陈述了以下内容: 但是,包装必须初始化,这会导致最终用户可能忘记调用初始化式。如何才能以干净透明的方式做到这一点?...

以下可能是一个解决方案。 它仍需要初始化,但如果用户尚未执行此操作,则将引发错误。

我定义了一个处理函数指针的类型closure

! file closure.f90
module closure_m
  implicit none

  type closure
    private
    procedure(f1), pointer, nopass :: f1ptr => null()
    procedure(f3), pointer, nopass :: f3ptr => null()
    real :: a, b
  contains
    generic   :: init => closure_init_f1, closure_init_f3
      !! this way by calling obj%init one can call either of the two closure_init_fX procedures
    procedure :: exec => closure_exec
    procedure :: closure_init_f1, closure_init_f3
  end type

  abstract interface
    real function f1(x)
      real, intent(in) :: x
    end function

    real function f3(a, b, x)
      real, intent(in) :: a, b, x
    end function
  end interface

contains

  subroutine closure_init_f1(this, f)
    class(closure), intent(out) :: this
    procedure(f1)               :: f

    this%f1ptr => f
    this%f3ptr => null()
  end subroutine

  subroutine closure_init_f3(this, f, a, b)
    class(closure), intent(out) :: this
    procedure(f3)               :: f
    real,           intent(in)  :: a, b

    this%f1ptr => null()
    this%f3ptr => f
    this%a     =  a
    this%b     =  b
  end subroutine

  real function closure_exec(this, x) result(y)
    class(closure), intent(in) :: this
    real,           intent(in) :: x

    if      (associated(this%f1ptr)) then
      y = this%f1ptr(x)
    else if (associated(this%f3ptr)) then
      y = this%f3ptr(this%a, this%b, x)
    else
      error stop "Initialize the object (call init) before computing values (call exec)!"
    end if
  end function

end module

关于行class(closure), intent(out) :: this: 这是为Fortran类型编写初始值设定项的标准方法。 请注意,它是class而不是type,这使得this成为类型绑定过程所需的多态。

我稍微调整了您的函数模块(更改了数据类型)

! file fns.f90
module fns_m
contains
  real function f(a, b, x)
    real, intent(in) :: a, b, x
    f = (a-b)*x
  end function

 real function g(x)
    real, intent(in) :: x
    g = x**2
 end function
end module

示例程序

! file a.f90
program main
  use closure_m
  use fns_m

  implicit none

  type(closure) :: c1, c2

  call c1%init(g)
  print *, c1%exec(2.0)

  call c1%init(f, 1.0, 2.0)
  print *, c1%exec(2.0)

  call c2%init(f, 1.0, -2.0)
  print *, c2%exec(3.0)
end program

输出示例

$ gfortran closure.f90 fns.f90 a.f90 && ./a.out
   4.00000000    
  -2.00000000    
   9.00000000    

这篇关于Fortran中的程序指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆