Массивы указателей на функции в Фортране - PullRequest
11 голосов
/ 26 марта 2010

Я могу создавать указатели функций в Fortran 90, с кодом вроде

real, external :: f

и затем используйте f в качестве аргумента для другой функции / подпрограммы. Но что, если я хочу массив указателей на функции? В C я бы просто сделал

double (*f[])(int);

для создания массива функций, возвращающих double и принимающих целочисленный аргумент. Я попробовал самое очевидное,

real, external, dimension(3) :: f

но gfortran не позволяет мне смешивать EXTERNAL и DIMENSION. Есть ли способ сделать то, что я хочу? (Контекст для этого - программа для решения системы дифференциальных уравнений, поэтому я мог вводить уравнения, не имея миллиона параметров в моих подпрограммах.)

1 Ответ

17 голосов
/ 26 марта 2010

Объявление «real, external :: f» на самом деле не превращает «f» в полный указатель, поскольку вы не можете изменить процедуру, на которую он указывает, - это позволяет вам передать эту единственную функцию в другую подпрограмму ., Поэтому вам также нужен атрибут указателя. Есть примеры на странице 267 «Фортрана 95/2003 объяснено» Metcalf, Reid & Cohen - поиск в Google по «указателю процедуры fortran» откроет эту страницу. Простой пример, близкий к вашему, это "real, external, pointer :: f_ptr". В качестве альтернативы: "процедура (f), указатель :: 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
...