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

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

Переменное имя подпрограммы, переданное в качестве аргумента, является типом данных. Где он хранится? Как я могу получить к нему доступ?

Вот еще объяснение. G — процедура нелинейной подгонки. H использует G, но с группировкой параметров (итерация перемещает одну группу за раз). G использует общую подпрограмму прямой модели, имя которой передается в качестве аргумента. Я хотел бы, чтобы H сохранил эту общность.

Вот тестовая программа, использующая обходной путь с жестко заданным именем подпрограммы:

  module G_MOD
  implicit none
  character(len=30)::message='Good Morning'

  contains

  subroutine G(Sub)
  external::Sub
  call Sub
  end subroutine G

  end module G_MOD

  module H_MOD
  use G_MOD
  implicit none

  contains

  subroutine H(sub)
  external:: sub
  call G(LocalSub)
  end subroutine H

  subroutine LocalSub
  external:: MySub
  message='Good Afternoon'
  call G(MySub) ! the subroutine name "MySub" is hardcoded
                ! I would like it to be argument sub
  end subroutine LocalSub

  end module H_MOD

  program test
  use H_MOD
  implicit none
  external MySub
  call H(MySub)
  end program test

  subroutine MySub
  use G_MOD,only:message
  write(*,*)trim(Message)
  end subroutine MySub

person user3772612    schedule 10.06.2017    source источник
comment
Используйте тег fortran для всех вопросов Fortran, чтобы привлечь больше внимания.   -  person Vladimir F    schedule 11.06.2017
comment
Не используйте external, если у вас есть модули. В Fortran 2003 есть хорошие способы. Вам по какой-то причине нужен строгий старый Fortran 95?   -  person Vladimir F    schedule 12.06.2017
comment
Возможный дубликат Как изменить имя процедуры передается как аргумент?   -  person Vladimir F    schedule 13.06.2017


Ответы (1)


Решение 1

Вам не нужно ничего хранить, если вы сделаете LocalSub внутренним для H:

  subroutine H(sub)
    external:: sub
    call G(LocalSub)
  contains
    subroutine LocalSub
      message='Good Afternoon'
      call G(sub)
    end subroutine LocalSub
  end subroutine H

Требуется Фортран 2008.

С некоторой очисткой, отступом для удобства чтения, удалением уродливых внешних элементов с использованием абстрактного интерфейса (Fortran 2003, но external можно избежать даже в Fortran 90 с использованием интерфейсных блоков) код выглядит следующим образом:

  module G_MOD
    implicit none
    character(len=30)::message='Good Morning'

    abstract interface
      subroutine sub_interface
      end subroutine
    end interface

  contains

    subroutine G(Sub)
      procedure(sub_interface) :: sub
      call Sub
    end subroutine G

  end module G_MOD

  module H_MOD
    use G_MOD
    implicit none

  contains

    subroutine H(sub)
      procedure(sub_interface) :: sub
      call G(LocalSub)
    contains
      subroutine LocalSub

        message='Good Afternoon'
        call G(sub) 
      end subroutine LocalSub
    end subroutine H

  end module H_MOD

  program test
    use H_MOD
    implicit none


    call H(MySub)
  contains
    subroutine MySub
      use G_MOD,only:message
      write(*,*)trim(Message)
    end subroutine MySub
  end program test

Решение 2

Если вы действительно хотите сохранить ссылку на процедуру в модуле, это возможно, но помните, что глобальные переменные УЖАСНЫ. Что делать, если вы хотите сделать несколько вызовов оптимизации параллельно?

Таким образом, вы можете хранить адрес (не имя) процедуры в файле procedure pointer. Для этого требуется Fortran 2003. Минимальное изменение вашего кода

  module H_MOD
    use G_MOD
    implicit none

    procedure, pointer :: stored_sub => null()

  contains

    subroutine H(sub)
      external:: sub
      stored_sub => sub
      call G(LocalSub)
    end subroutine H

    subroutine LocalSub
      message='Good Afternoon'
      call G(stored_sub)
    end subroutine LocalSub

  end module H_MOD

но гораздо лучший современный код:

  module G_MOD
    implicit none
    character(len=30)::message='Good Morning'

    abstract interface
      subroutine sub_interface
      end subroutine
    end interface

  contains

    subroutine G(Sub)
      procedure(sub_interface) :: sub
      call Sub
    end subroutine G

  end module G_MOD

  module H_MOD
    use G_MOD
    implicit none

    procedure(sub_interface), pointer :: stored_sub => null()

  contains

    subroutine H(sub)
      procedure(sub_interface) :: sub
      stored_sub => sub
      call G(LocalSub)

    end subroutine H

    subroutine LocalSub

      message='Good Afternoon'
      call G(stored_sub) 
    end subroutine LocalSub

  end module H_MOD


  module MySub_module
  contains
    subroutine MySub
      use G_MOD,only:message
      write(*,*)trim(Message)
    end subroutine MySub
  end module MySub_module

  program test
    use H_MOD
    use MySub_module
    implicit none


    call H(MySub)
  end program test

Тем не менее, я определенно предпочитаю вариант с внутренней процедурой.

И помните, используйте отступы, это необходимо для читаемого кода.

person Vladimir F    schedule 12.06.2017
comment
что произойдет, если вы измените его? - person Vladimir F; 13.06.2017
comment
Модификация заключается в том, чтобы добавить вызов строки stored_sub перед вызовом строки G (stored_sub). Это должно работать так же и привести к двум сообщениям «Добрый день». Однако это приводит к сбою компиляции с G95, но не с Intel (в файле solution2.for:36 вызовите store_sub 1 Error: Symbol 'stored_sub' в (1) не имеет IMPLICIT типа. - person user3772612; 14.06.2017
comment
Какая-то ошибка в G95. Забудьте о G95, он устарел и больше не поддерживается. Вместо этого используйте gfortran. - person Vladimir F; 14.06.2017