Как получить указатель на процедуру Фортрана в качестве компонента производного типа, который указывает на процедуру с привязкой к типу в расширении этого типа? - PullRequest
0 голосов
/ 16 мая 2018

Я проверил похожие вопросы и соответствующие учебники, но не могу найти решение этой проблемы.

Примечание: это использует современный Фортран.

Итак, я хочу иметь базовый тип,например, base, которая содержит процедуру с привязкой к типу, например, run, которая делегирует подпрограмме в типах, расширяющих базу, например, type, extends(base) :: my_extension.Давайте назовем подпрограмму, которой мы хотим делегировать my_procedure.

. Я могу сделать это довольно запутанным способом, сделав base абстрактным, сделав base содержащей отложенную процедуру, например delegate,получение run для делегирования на delegate, затем реализация delegate в my_extension и получение его для делегирования на my_procedure.

Однако, это грязно, так как требуются типы, расширяющие baseреализовать delegate, но все реализации просто делегируют какой-то другой процедуре.Это еще более усложняется тем фактом, что я обычно хочу несколько экземпляров my_extension, где каждый экземпляр делегирует свою процедуру в пределах my_extension, и в этом случае мне нужно сохранять my_extension абстрактным, расширять my_extension и реализовывать delegate вот так я получаю столько расширений, сколько у меня есть процедур!

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

base.f90:

module base_mod

    implicit none

    type base
        procedure(my_interface), pointer :: ptr  ! Pointer component
    contains
        procedure :: run  ! Type-bound procedure
    end type base

    abstract interface
        subroutine my_interface(self)
            import :: base
            class(base) :: self  ! This is a problem...
        end subroutine my_interface
    end interface


contains

    subroutine run(self)
        class(base) :: self
        call self%ptr()
    end subroutine run


end module base_mod

my_extension.f90:

module my_extension_mod

    use base_mod

    implicit none

    type, extends(base) :: my_extension
    contains
        procedure :: my_procedure
    end type my_extension


contains

    subroutine my_procedure(self)
        class(my_extension) :: self  ! ...because this is different.
        ! Do useful stuff, e.g.
        print *, "my_procedure was run"
    end subroutine my_procedure

end module my_extension_mod

main.f90:

program main

    use my_extension_mod

    implicit none

    type(my_extension) :: my_instance
    procedure(my_interface), pointer :: my_ptr
    my_ptr => my_procedure
    my_instance = my_extension(my_ptr)  ! Use implicit constructor
    call my_instance%run()  ! Expect to see "my_procedure was run" printed

end program main

make.sh:

#! /bin/bash
gfortran -c base.f90
gfortran -c my_extension.f90
gfortran base.o my_extension.o main.f90

Однако компилятор жалуется следующим образом:

main.f90:9.14:

    my_ptr => my_procedure
          1
Error: Interface mismatch in procedure pointer assignment at (1): Type/rank mismatch in argument 'self'

Это потому, что my_interface ожидает объект класса base какinput, тогда как my_procedure имеет объект класса my_extension в качестве input, поэтому технически интерфейсы не совпадают.Тем не менее, my_extension расширяет base, поэтому, в некотором смысле, это должно быть в порядке (но, очевидно, не в порядке, что касается компилятора).

Итак, мой вопрос: как я могу получитьмимо этой проблемы?Как я могу иметь интерфейс, который работает для my_procedure, но все еще работает для других процедур других типов, которые расширяют base (например, те, что в my_other_extension)?Или как я могу иметь указатели на процедуры в расширениях base без использования интерфейса?Или как мне добиться того, что я пытаюсь сделать другим способом (например, без использования указателей), но при этом избегая грязного метода абстрактного типа, описанного сверху?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...