Function pointer arrays in Fortran

12,335

The declaration "real, external :: f" doesn't really make "f" into a full pointer since you can't change the procedure that it points -- it does permit you to pass this single function to another routine., So you also need the "pointer" attribute. There are examples on page 267 of "Fortran 95/2003 explained" by Metcalf, Reid & Cohen -- a google search for "fortran procedure pointer" will bring up this page. A simple example close to yours is "real, external, pointer :: f_ptr". Alternatively: "procedure (f), pointer :: f_ptr". This is a Fortran 2003 feature -- http://gcc.gnu.org/wiki/Fortran2003 and http://gcc.gnu.org/wiki/ProcedurePointers lists partial support in gfortran, best with 4.5. I'm not sure whether "dimension" is directly allowed, but you can assign a procedure to a pointer, which provides a lot of flexibility. You can also put the pointer into a derived type, which could be made into an array.

Edit: here is a code example which works with gfortran 4.5: Edit 2: line commented out per comments below.

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
Share:
12,335

Related videos on Youtube

Eduardo Dobay
Author by

Eduardo Dobay

Updated on March 14, 2020

Comments

  • Eduardo Dobay
    Eduardo Dobay over 3 years

    I can create function pointers in Fortran 90, with code like

    real, external :: f
    

    and then use f as an argument to another function/subroutine. But what if I want an array of function pointers? In C I would just do

    double (*f[])(int);
    

    to create an array of functions returning double and taking an integer argument. I tried the most obvious,

    real, external, dimension(3) :: f
    

    but gfortran doesn't let me mix EXTERNAL and DIMENSION. Is there any way to do what I want? (The context for this is a program for solving a system of differential equations, so I could input the equations without having a million parameters in my subroutines.)

  • AlanSE
    AlanSE almost 12 years
    Your code runs correctly with gfortran but does not compile with either g95 or the Intel Fortran compiler. I've saved the error messages and would be happy to post them, where would be an appropriate place to do so?
  • AlanSE
    AlanSE almost 12 years
    Both compiler messages are similar, and both are at line 51 (after the implicit none) at variable "func". ifort says "error #6409: This name has already been used as an external procedure name" and g95 says "Symbol 'func' at (1) conflicts with the same name in an encompassing program unit". I hope that sufficiently identifies the error. Again, gfortran is not bothered by this.
  • AlanSE
    AlanSE almost 12 years
    Yeah, I think that "pointer :: func" line just shouldn't be there. I'm not sure what that was supposed to accomplish, there's no reason to suspect there would be a problem without it.

Related