问题 Fortran中的函数指针数组


我可以在Fortran 90中创建函数指针,代码类似

real, external :: f

然后使用 f 作为另一个函数/子例程的参数。但是,如果我想要一个 排列 函数指针?在C中我会这样做

double (*f[])(int);

创建一个返回double并取整数参数的函数数组。我试过最明显的,

real, external, dimension(3) :: f

但是gfortran并没有让我混合EXTERNAL和DIMENSION。有什么办法可以做我想要的吗? (这个上下文是一个求解微分方程组的程序,所以我可以在子程序中输入方程而没有一百万个参数。)


2549
2018-03-26 03:59


起源



答案:


声明“real,external :: f”并没有真正将“f”变成一个完整的指针,因为你无法改变它指向的过程 - 它允许你将这个单一的函数传递给另一个例程。你还需要“指针”属性。 Metcalf,Reid&Cohen在“Fortran 95/2003解释”的第267页上有一些例子 - 谷歌搜索“fortran程序指针”将显示此页面。一个接近你的简单例子是“real,external,pointer :: f_ptr”。或者:“procedure(f),pointer :: f_ptr”。这是Fortran 2003功能 - http://gcc.gnu.org/wiki/Fortran2003 和 http://gcc.gnu.org/wiki/ProcedurePointers 列出了gfortran中的部分支持,最好是4.5。我不确定是否直接允许“维度”,但您可以为指针分配一个过程,这提供了很大的灵活性。您还可以将指针放入派生类型,该类型可以制作成数组。

编辑:这是一个与gfortran 4.5一起使用的代码示例: 编辑2:行注释掉下面的评论。

module ExampleFuncs

  implicit none

contains

function f1 (x)
  real :: f1
  real, intent (in) :: x

  f1 = 2.0 * x

  return
end function f1


function f2 (x)
   real :: f2
   real, intent (in) :: x

   f2 = 3.0 * x**2

   return
end function f2


function fancy (func, x)

   real :: fancy
   real, intent (in) :: x

   interface AFunc
      function func (y)
         real :: func
         real, intent (in) ::y
      end function func
   end interface AFunc

   fancy = func (x) + 3.3 * x

end function fancy

end module  ExampleFuncs

program test_proc_ptr

  use ExampleFuncs

  implicit none

  ! REMOVE: pointer :: func
  interface
     function func (z)
        real :: func
        real, intent (in) :: z
     end function func
  end interface

  procedure (func), pointer :: f_ptr => null ()

  type Contains_f_ptr
     procedure (func), pointer, nopass :: my_f_ptr
  end type Contains_f_ptr

  type (Contains_f_ptr), dimension (2) :: NewType


  f_ptr => f1
  write (*, *) f_ptr (2.0)
  write (*, *) fancy (f_ptr, 2.0)

  f_ptr => f2
  write (*, *) f_ptr (2.0)
  write (*, *) fancy (f_ptr, 2.0)

  NewType(1) % my_f_ptr => f1
  NewType(2) % my_f_ptr => f2

  write (*, *) NewType(1) % my_f_ptr (3.0), NewType(2) % my_f_ptr (3.0)

  stop

end program test_proc_ptr

16
2018-03-26 04:43



您的代码可以使用gfortran正确运行,但不能使用g95或Intel Fortran编译器进行编译。我已经保存了错误消息,并很乐意发布它们,哪里适合这样做? - AlanSE
两个编译器消息都是相似的,并且两者都在变量“func”的第51行(在隐式none之后)。 ifort表示“错误#6409:此名称已被用作外部程序名称”,g95表示“(1)处的符号'func'与包含程序单元中的相同名称冲突”。我希望能够充分识别错误。再一次,gfortran并不为此烦恼。 - AlanSE
是的,我认为“pointer :: func”行不应该存在。我不确定应该完成什么,没有理由怀疑没有它会有问题。 - AlanSE


答案:


声明“real,external :: f”并没有真正将“f”变成一个完整的指针,因为你无法改变它指向的过程 - 它允许你将这个单一的函数传递给另一个例程。你还需要“指针”属性。 Metcalf,Reid&Cohen在“Fortran 95/2003解释”的第267页上有一些例子 - 谷歌搜索“fortran程序指针”将显示此页面。一个接近你的简单例子是“real,external,pointer :: f_ptr”。或者:“procedure(f),pointer :: f_ptr”。这是Fortran 2003功能 - http://gcc.gnu.org/wiki/Fortran2003 和 http://gcc.gnu.org/wiki/ProcedurePointers 列出了gfortran中的部分支持,最好是4.5。我不确定是否直接允许“维度”,但您可以为指针分配一个过程,这提供了很大的灵活性。您还可以将指针放入派生类型,该类型可以制作成数组。

编辑:这是一个与gfortran 4.5一起使用的代码示例: 编辑2:行注释掉下面的评论。

module ExampleFuncs

  implicit none

contains

function f1 (x)
  real :: f1
  real, intent (in) :: x

  f1 = 2.0 * x

  return
end function f1


function f2 (x)
   real :: f2
   real, intent (in) :: x

   f2 = 3.0 * x**2

   return
end function f2


function fancy (func, x)

   real :: fancy
   real, intent (in) :: x

   interface AFunc
      function func (y)
         real :: func
         real, intent (in) ::y
      end function func
   end interface AFunc

   fancy = func (x) + 3.3 * x

end function fancy

end module  ExampleFuncs

program test_proc_ptr

  use ExampleFuncs

  implicit none

  ! REMOVE: pointer :: func
  interface
     function func (z)
        real :: func
        real, intent (in) :: z
     end function func
  end interface

  procedure (func), pointer :: f_ptr => null ()

  type Contains_f_ptr
     procedure (func), pointer, nopass :: my_f_ptr
  end type Contains_f_ptr

  type (Contains_f_ptr), dimension (2) :: NewType


  f_ptr => f1
  write (*, *) f_ptr (2.0)
  write (*, *) fancy (f_ptr, 2.0)

  f_ptr => f2
  write (*, *) f_ptr (2.0)
  write (*, *) fancy (f_ptr, 2.0)

  NewType(1) % my_f_ptr => f1
  NewType(2) % my_f_ptr => f2

  write (*, *) NewType(1) % my_f_ptr (3.0), NewType(2) % my_f_ptr (3.0)

  stop

end program test_proc_ptr

16
2018-03-26 04:43



您的代码可以使用gfortran正确运行,但不能使用g95或Intel Fortran编译器进行编译。我已经保存了错误消息,并很乐意发布它们,哪里适合这样做? - AlanSE
两个编译器消息都是相似的,并且两者都在变量“func”的第51行(在隐式none之后)。 ifort表示“错误#6409:此名称已被用作外部程序名称”,g95表示“(1)处的符号'func'与包含程序单元中的相同名称冲突”。我希望能够充分识别错误。再一次,gfortran并不为此烦恼。 - AlanSE
是的,我认为“pointer :: func”行不应该存在。我不确定应该完成什么,没有理由怀疑没有它会有问题。 - AlanSE