Я проверил похожие вопросы и соответствующие учебники, но не могу найти решение этой проблемы.
Примечание: это использует современный Фортран.
Итак, я хочу иметь базовый тип,например, 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
без использования интерфейса?Или как мне добиться того, что я пытаюсь сделать другим способом (например, без использования указателей), но при этом избегая грязного метода абстрактного типа, описанного сверху?