Skip to Content

Массив указателей на функции

Встала задача такой организации вычислений, когда вызов необходимой процедуры следует осуществлять по индексу.
Фактически — необходимо создать массив указателей на процедуры.
В Фортране это затруднено тем, что описание вроде

real, pointer, dimension(:) :: a

задаёт не массив указателей на объекты вещественного типа, а указатель на вещественный массив.

Однако, ситуация разрешима в рамках стандарта F2003.

Для этого необходимо описать структуру, содержащую поле — указатель на процедуру соответствующего вида.
После чего организовать массив таких структур. Соответственно, после присвоения указателей, вызов процедуры будет выглядеть как обращение к полю-указателю соответствующего элемента массива.

Чтобы создать указатель на процедуру (поле задаваемой структуры), необходимо описать интерфейс указанной процедуры. Так как процедур у нас несколько, ситуация разрешается через описание абстрактного интерфейса.

В общем виде решение на примере может выглядеть так, как это показано ниже.

funcs.f90

Записываем модуль, содержащий две функции, общий (одинаковый) для них абстрактный интерфейс и новый тип func_pointer, содержащий только одно поле f_pointer — указатель на процедуру, имеющую интерфейс наших функций.

module funcs

    implicit none

! Описываем универсальный (абстрактный) интерфейс
! для используемых процедур
    abstract interface
        function func (a,b) result (c)
            real :: a, b, c
        end function func
    end interface

! Вводим новый тип, задающий указатель на процедуру,
! описанную в интерфейсе
    type func_pointer
        procedure (func), pointer, nopass :: f_pointer
    end type

contains

! Задаём пару функций для примера.

function plus (x,y) result (p)
    real :: x, y, p
    p = x + y
end function plus

function minus (x,y) result (m)
    real :: x, y, m
    m = x-y
end function minus

end module funcs

main.f90

В основной программной единице описываем массив типа func_pointer, размещаем его и присваиваем полю f_pointer каждого из элементов массива указатель на соответствующую функцию. Теперь вызов функции может осуществляться через обращение к массиву functions с указанием индекса и поля-указателя.

program test

    use funcs
    implicit none

! Создаём массив типа func_pointer -- массив
! указателей на процедуры
    type(func_pointer), dimension(:), allocatable :: functions
    integer :: i
    real :: x, y

! Размещаем массив и присваиваем его элементам 
! указатели на соответствующие процедуры
    allocate (functions(2))
    functions(1) % f_pointer => plus
    functions(2) % f_pointеr => minus

    read (*,*) i, x, y 

! Вызываем процедуру через указатель по её индексу
    write (*,*) functions(i) % f_pointer(x,y)

end program test