Class Fortran 2008-类(*)的用户定义I/O过程

Class Fortran 2008-类(*)的用户定义I/O过程,class,io,fortran,polymorphism,fortran2008,Class,Io,Fortran,Polymorphism,Fortran2008,我正在尝试创建一个类型,它可以作为任意其他类型的包装器,因此我可以创建一个异构数组,正如和中建议的那样 所以,我试着这样实现它: module m implicit none type :: container class(*), pointer, public :: item end type container end module m program mwe use m implicit none type(container) :: cont integer, targ

我正在尝试创建一个类型,它可以作为任意其他类型的包装器,因此我可以创建一个异构数组,正如和中建议的那样

所以,我试着这样实现它:

module m
implicit none

type :: container
    class(*), pointer, public :: item
end type container
end module m

program mwe 
use m

implicit none

type(container) :: cont
integer, target :: i

i = 5 
cont = container(i)

write(*,*) cont%item

end program mwe 
module m
    implicit none

    type :: container
        class(*), pointer, public :: item
    contains
        procedure :: write_sample => write_container_sample_impl
        procedure :: read_sample  => read_container_sample_impl

        generic   :: write(unformatted) => write_sample
        generic   :: read(unformatted) => read_sample
    end type container

contains

    subroutine write_container_sample_impl(this, unit, iostat, iomsg)
        class(container), intent(in)    :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        write(unit, iostat=iostat, iomsg=iomsg) this%item
    end subroutine write_container_sample_impl

    subroutine read_container_sample_impl(this, unit, iostat, iomsg)
        class(container), intent(inout) :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        read(unit, iostat=iostat, iomsg=iomsg) this%item
    end subroutine read_container_sample_impl

end module m

program mwe 
    use m

    implicit none

    type(container) :: cont
    integer, target :: i

    i = 5 
    cont = container(i)

    write(*,*) cont%item

end program mwe 
现在我犯了一个错误

test4.f90(20): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
    write(*,*) cont%item
----^
compilation aborted for test4.f90 (code 1)
所以我尝试像这样实现I/O:

module m
implicit none

type :: container
    class(*), pointer, public :: item
end type container
end module m

program mwe 
use m

implicit none

type(container) :: cont
integer, target :: i

i = 5 
cont = container(i)

write(*,*) cont%item

end program mwe 
module m
    implicit none

    type :: container
        class(*), pointer, public :: item
    contains
        procedure :: write_sample => write_container_sample_impl
        procedure :: read_sample  => read_container_sample_impl

        generic   :: write(unformatted) => write_sample
        generic   :: read(unformatted) => read_sample
    end type container

contains

    subroutine write_container_sample_impl(this, unit, iostat, iomsg)
        class(container), intent(in)    :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        write(unit, iostat=iostat, iomsg=iomsg) this%item
    end subroutine write_container_sample_impl

    subroutine read_container_sample_impl(this, unit, iostat, iomsg)
        class(container), intent(inout) :: this
        integer, intent(in)         :: unit
        integer, intent(out)        :: iostat
        character(*), intent(inout) :: iomsg

        read(unit, iostat=iostat, iomsg=iomsg) this%item
    end subroutine read_container_sample_impl

end module m

program mwe 
    use m

    implicit none

    type(container) :: cont
    integer, target :: i

    i = 5 
    cont = container(i)

    write(*,*) cont%item

end program mwe 
但即使在我的新方法中也会出现同样的错误:

test4.f90(22): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
        write(unit, iostat=iostat, iomsg=iomsg) this%item
--------^
test4.f90(31): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
        read(unit, iostat=iostat, iomsg=iomsg) this%item
--------^
test4.f90(47): error #5513: A polymorphic I/O list item requires a user-defined derived-type input/output procedure.
    write(*,*) cont%item
----^

因此,我有两个问题:

  • 我应该如何正确地实施它
  • 将项变量声明为指针还是可分配变量更好/更容易

  • 使用无限多态实体是一项艰巨的任务

    为容器类型添加定义的输入/输出过程并不能解决问题,因为问题不在于容器本身。相反,它是容器的组件,它是多态的,需要定义的I/O过程

    但不幸的是,由于该组件是无限多态的,因此不可能定义这样的过程。1

    此外,您为容器类型定义的I/O过程实际上不会被使用。您只为未格式化的输入和输出定义了过程,但
    write(*,*)
    是(列表导向的)格式化输出

    至于如何解决这个问题:在某个时候,你必须决定你的无限多态实体是什么。使用无限多态实体的部分原因是,不能将内部类型和派生类型视为同一类型。与您前面的问题一样,如果您可以使用
    class(非星级)
    而不是
    class(*)
    ,您会发现生活会更轻松

    考虑到事情的现状,
    选择类型
    可能是你最大的希望



    1定义的I/O过程可能只存在于派生类型。

    我实现类似内容的方式如下

    module container_mod
    
    implicit none
    private
    !Public access vars
    public :: container
    
    type container !< Unlimited polymorphic container class 
        private !contents are only accessible trough the methods, no direct access is allowed
        class(*), pointer :: value => null() !< value stored in container
    contains
    procedure :: getContent     !< returns stored content (pointer)
    procedure :: storeContent   !< stores the provided values (sourced allocation)
    procedure :: printContainer !< prints container contents (only primitive types implemented)
    end type container
    
    interface container
        procedure constructor !< construct/initialize a container
    end interface
    
    function getContent(this)
    class(container), intent(in) :: this
    class(*), pointer :: getContent
    getContent => this%value
    end function getContent
    
    subroutine storeContent(this,to_store)
    class(container), intent(inout) :: this
    class(*), intent(in) :: to_store
    allocate(this%value, source=to_store)
    end subroutine storeContent
    
    subroutine printContainer(this)
    class(container), intent(in) :: this
    select type(v => this%value)
    type is (integer)
        print *, v
    type is (character(*))
        print *, v(1:1)
    type is (real)
        print *, v
        class default
        print*, "[printContainer]: don't know how to print this value, ignoring"
    end select
    end subroutine printContainer
    
    function constructor(to_store)
    class(container), pointer :: constructor
    class(*), intent(in) :: to_store
    allocate(constructor)
    allocate(constructor%value, source=to_store)
    end function constructor
    
    检查它实现了一个容器类并在抽象异构数组中使用它


    一旦检索到数组的内容,恐怕就没有办法绕过typeguards了,这是Fortran为您准备的。如果你真的找到办法,请告诉我

    至于你的第二个问题:我的观点是,我们应该始终使用可分配变量,而不是指针的特定功能(例如指向同一目标或指向同一目标的部分的多个指针)是不必要的。首先,该语言保证分配的实体在超出作用域时将自动解除分配,因此很难对内存泄漏进行编程。就我个人而言,我发现它们比指针和目标更容易使用。嗨,欢迎来到stack overflow。您应该查看帮助中心的“关于”部分,由链接和其他链接组成的答案不是最佳选择,因为将来可能无法访问该链接,从而导致答案无效