Как использовать указатели процедур для подпрограмм с разным количеством аргументов

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

program main
use boundary
implicit none

  bc1 => boundaryA
  bc2 => boundaryB
  bc3 => boundaryC

  call comp_boundary

end program

Я определяю все граничные операции «boundaryA/B/C» в «граничном» модуле.

module boundary
implicit none

procedure(boundary_type), pointer :: bc1,bc2,bc3

abstract interface
  subroutine boundary_type(i)
    integer :: i
  end subroutine
end interface

contains

subroutine boundaryA(i)
integer :: i
  print*, 'Boundary A at ',i
end subroutine

subroutine boundaryB(i)
integer :: i
  print*, 'Boundary B at ',i
end subroutine

subroutine boundaryC(i)
integer :: i
  print*, 'Boundary C at',i
end subroutine

subroutine comp_boundary
  call bc1(1)
  call bc2(2)
  call bc3(3)
end subroutine

end module

Это хорошо работает.

Но мой вопрос в том, что если, скажем, boundaryC имеет не один входной аргумент, а два, то мое определение для абстрактного интерфейса boundary_type сейчас не работает.

Можно ли использовать указатель процедуры для решения этого случая? Или как-то иначе?


person zljt3216    schedule 17.01.2018    source источник
comment
Как код, вызывающий bcN, узнает, что ему нужно предоставить два аргумента?   -  person IanH    schedule 17.01.2018
comment
Я предлагаю вам использовать некоторые отступы. Это имеет огромное значение в читабельности вашего кода. Вам также не нужно повторять implicit none в каждой подпрограмме модуля. Один раз в модуле достаточно.   -  person Vladimir F    schedule 17.01.2018
comment
Думаю, это тоже мой вопрос. Можно ли здесь использовать какой-то общий интерфейс? @IanH   -  person zljt3216    schedule 17.01.2018
comment
Предположим, можно было бы написать общий интерфейс для процедур, которые принимают один или два аргумента, который просто подталкивает решение о том, какую процедуру (или интерфейс) вызывать где-то еще в пути кода. Возможно, вы могли бы переписать процедуру с двумя аргументами в форму с одним аргументом и заставить ее вызывать другой аргумент. Какой бы вариант вы ни выбрали, вы должны соответствующим образом разработать свою программу. Лично я не считаю интерфейс подходящим местом для принятия решения   -  person High Performance Mark    schedule 17.01.2018
comment
@HighPerformanceMark, да, переписывание процедуры с двумя аргументами может быть одним из решений на данный момент. Я также проведу некоторое исследование, чтобы ознакомиться с общим кодированием на Фортране и, возможно, откажусь от программы.   -  person zljt3216    schedule 17.01.2018
comment
Универсальный интерфейс позволяет вам вызывать разные процедуры, которые имеют одно и то же имя, в зависимости от типа и типа предоставленных аргументов. Я не думаю, что это уместно здесь - вы знаете конкретную процедуру для вызова - у вас есть указатель, указывающий на нее. Что вам нужно описать нам, так это характер потока информации для процедуры. Возможно, решение состоит в том, чтобы вызов предоставлял максимальную информацию (несколько аргументов) независимо от того, что вызывается, возможно, информация должна быть связана с процедурой в объекте.   -  person IanH    schedule 18.01.2018


Ответы (1)


Вы можете добиться этого с помощью аргумента OPTIONAL. Это скорее академическое решение, поскольку всегда есть сохранение страданий. Как комментарий Высокая производительность Марк утверждает, что ваше решение использовать один или два аргумента должно быть где-то принято.

Тем не менее, аргумент OPTIONAL потребует добавить это также ко всем подпрограммам и, следовательно, может быть не совсем тем решением, которое вы запрашиваете, поскольку все подпрограммы существенно изменены. По сути, это то же самое решение, которое вы дали, только с другим набором аргументов процедуры.

MODULE boundary
  IMPLICIT NONE

  PROCEDURE(boundary_type), POINTER :: bc1,bc2

  ABSTRACT INTERFACE
     SUBROUTINE boundary_type(i,j)
       INTEGER           :: i
       INTEGER, OPTIONAL :: j
     END SUBROUTINE boundary_type
  END INTERFACE

CONTAINS

  SUBROUTINE boundaryA(i,j)
    INTEGER           :: i
    INTEGER, OPTIONAL :: j
    PRINT *, 'Boundary A at ',i
  END SUBROUTINE boundaryA

  SUBROUTINE boundaryB(i,j)
    INTEGER           :: i
    INTEGER, OPTIONAL :: j
    PRINT *, 'Boundary B at ',i,j
  END SUBROUTINE boundaryB

  SUBROUTINE comp_boundary
    CALL bc1(1)
    CALL bc2(2,3)
  END SUBROUTINE comp_boundary

END MODULE boundary

Примечание: подпрограмма boundaryB должна всегда вызываться с обоими аргументами, поскольку не выполняется проверка доступности j (с использованием PRESENT).

person kvantour    schedule 18.01.2018