简体   繁体   中英

How to write an allocatable array in a derived type using namelists?

I am having trouble writing an allocatable array nested in a derived type using namelists. A minimal example is shown below. How can I modify the program to have the allocatable array inside the derived type work as though it were not nested?

program test

    implicit none

    type struct_foo
        integer, allocatable :: nested_bar(:)
    end type struct_foo

    integer, allocatable :: bar(:)
    type(struct_foo) :: foo
    ! namelist / list / foo, bar
    namelist / list / bar

    allocate(bar(5))
    bar = [1:5]

    allocate(foo%nested_bar(5))
    foo%nested_bar=[1:5]

    write(*,list)

end program test

With the foo commented out of the namelist, it works just fine, producing the output:

 &LIST
 BAR     =           1,           2,           3,           4,           5
 /

With foo included, the program fails to compile:

>> ifort -traceback test_1.f90 -o test && ./test
test_1.f90(20): error #5498: Allocatable or pointer derived-type fields require a user-defined I/O procedure.
    write(*,list)
--------^
compilation aborted for test_1.f90 (code 1)

As the error message states, you need to provide a user defined derived type I/O (UDDTIO) procedure. This is required for input/output of any object with an allocatable or pointer component.

How the object of derived type is formatted in the file is completely under the control of the UDDTIO procedure.

An example, using a very simple output format, is below. Typically a UDDTIO procedure implementing namelist output would use an output format that was consistent with the other aspects of namelist output and typically there would also be a corresponding UDDTIO procedure that was then able to read the formatted results back in.

module foo_mod
  implicit none

  type struct_foo
    integer, allocatable :: nested_bar(:)
  contains
    procedure, private :: write_formatted
    generic :: write(formatted) => write_formatted
  end type struct_foo
contains
  subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg)
    class(struct_foo), intent(in) :: dtv
    integer, intent(in) :: unit
    character(*), intent(in) :: iotype
    integer, intent(in) :: v_list(:)
    integer, intent(out) :: iostat
    character(*), intent(inout) :: iomsg

    integer :: i

    if (allocated(dtv%nested_bar)) then
      write (unit, "(l1,i10,i10)", iostat=iostat, iomsg=iomsg)   &
          .true.,  &
          lbound(dtv%nested_bar, 1),  &
          ubound(dtv%nested_bar, 1)
      if (iostat /= 0) return
      do i = 1, size(dtv%nested_bar)
        write (unit, "(i10)", iostat=iostat, iomsg=iomsg)  &
            dtv%nested_bar(i)
        if (iostat /= 0) return
      end do
      write (unit, "(/)", iostat=iostat, iomsg=iomsg)
    else
      write (unit, "(l1,/)", iostat=iostat, iomsg=iomsg) .false.
    end if
  end subroutine write_formatted
end module foo_mod

program test
  use foo_mod

  implicit none

  integer, allocatable :: bar(:)
  type(struct_foo) :: foo
  namelist / list / foo, bar

  allocate(bar(5))
  bar = [1:5]

  allocate(foo%nested_bar(5))
  foo%nested_bar=[1:5]

  write (*,list)
end program test

Use of UDDTIO obviously requires a compiler that implements this Fortran 2003 language feature.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM