【问题标题】:Polymorphic dummy allocatable argument多态虚拟可分配参数
【发布时间】:2019-06-13 04:10:57
【问题描述】:

我有三个函数用于同一件事,但用于不同的虚拟参数类型:flip、flipLogical 和 flipInt。他们的代码实际上是完全相同的!还有另一个函数叫做flip3D,它只用于真正的虚拟参数,它从内部调用翻转。这就是现在一切正常的方式:

function flip(data)
   real, dimension(:,:), intent(in) :: data
   real, dimension(:,:), allocatable :: flip
   integer :: m, n, i

   m = size(data,1)
   n = size(data,2)

   allocate(flip(m,n))

   do i=1,m
      flip(m-i+1,:) = data(i,:)
   end do
 end function flip

 function flipLogical(data)
   logical, dimension(:,:), intent(in) :: data
   logical, dimension(:,:), allocatable :: flipLogical
   integer :: m, n, i

   m = size(data,1)
   n = size(data,2)

   allocate(flipLogical(m,n))

   do i=1,m
      flipLogical(m-i+1,:) = data(i,:)
   end do
 end function flipLogical

 function flipInt(data)
   integer, dimension(:,:), intent(in) :: data
   integer, dimension(:,:), allocatable :: flipInt
   integer :: m, n, i

   m = size(data,1)
   n = size(data,2)

   allocate(flipInt(m,n))

   do i=1,m
      flipInt(m-i+1,:) = data(i,:)
   end do
 end function flipInt

 function flip3D(data)
   real, dimension(:,:,:), intent(in) :: data
   real, dimension(:,:,:), allocatable :: flip3D
   integer :: m, n, o, j

   m = size(data, 1)
   n = size(data, 2)
   o = size(data, 3)

   allocate(flip3D(n, m, o))

   do j = 1, o
      flip3D(:,:,j) = flip(data(:,:,j))
   end do
 end function flip3D

虽然这工作得很好,但它非常丑陋。我想要一个多态函数翻转,它只适用于任何类型,我可以从 Flip3D 调用它,提供一个实变量作为虚拟参数。我正在尝试这样的事情:

function flip(data)
   class(*), dimension(:,:), intent(in) :: data
   class(*), dimension(:,:), allocatable :: flip
   integer :: m, n, i

   m = size(data,1)
   n = size(data,2)

   allocate(flip(m,n), mold=data)

   do i=1,m
      flip(m-i+1,:) = data(i,:)
   end do
 end function flip

但后来我收到错误

script.f90:698:7:

    flip(m-i+1,:) = data(i,:)
   1 Error: Nonallocatable variable must not be polymorphic in intrinsic assignment at (1) - check that there is a matching specific subroutine for '=' operator

script.f90:714:23:

    flip3D(:,:,j) = flip(data(:,:,j))
                   1 Error: Can't convert CLASS(*) to REAL(4) at (1)

【问题讨论】:

  • 一个子程序会更容易。
  • @VladimirF 更容易实现多态性?您能详细说明答案吗?我愿意改变。

标签: fortran polymorphism gfortran


【解决方案1】:

我会使用通过模板实现的通用函数来完成此操作,但请注意

function flip(data)
   class(*), dimension(:,:), intent(in) :: data
   class(*), dimension(:,:), allocatable :: flip
   integer :: i

   flip = data([(i,i=m,1,-1)],:)
 end function flip

用 gfortran 编译。

编辑:给定模板文件flip.i90

function Qflip(Qdata)
   dimension Qdata(:,:)
   intent(in) Qdata
   dimension Qflip(size(Qdata,1),size(Qdata,2))
   integer i

   do i = 1, size(Qdata,1)
      Qflip(size(Qdata,1)-i+1,:) = Qdata(i,:)
   end do
end function Qflip

我们可以编译flip.f90:

module real_mod
   implicit real(Q)
   private
   public flip
   interface flip
      module procedure Qflip
   end interface flip
   contains
include 'flip.i90'
end module real_mod

module Logical_mod
   implicit Logical(Q)
   private
   public flip
   interface flip
      module procedure Qflip
   end interface flip
   contains
include 'flip.i90'
end module Logical_mod

module Int_mod
   implicit integer(Q)
   private
   public flip
   interface flip
      module procedure Qflip
   end interface flip
   contains
include 'flip.i90'
end module Int_mod

module flip_mod
   use real_mod
   use Logical_mod
   use Int_mod
end module flip_mod

program flipmeoff
   use flip_mod
   implicit none
   real :: R(3,3) = reshape([ &
      1, 2, 3, &
      4, 5, 6, &
      7, 8, 9],shape(R),order=[2,1])
   Logical :: L(3,3) = reshape([ &
      .TRUE., .TRUE., .FALSE., &
      .FALSE., .TRUE., .FALSE., &
      .FALSE., .FALSE., .TRUE.],shape(L),order=[2,1])
   integer :: I(3,3) = reshape([ &
      1, 2, 3, &
      4, 5, 6, &
      7, 8, 9],shape(I),order=[2,1])
   write(*,'(3(f3.1:1x))') transpose(R)
   write(*,'()')
   write(*,'(3(f3.1:1x))') transpose(flip(R))
   write(*,'()')
   write(*,'(3(L1:1x))') transpose(L)
   write(*,'()')
   write(*,'(3(L1:1x))') transpose(flip(L))
   write(*,'()')
   write(*,'(3(i1:1x))') transpose(I)
   write(*,'()')
   write(*,'(3(i1:1x))') transpose(flip(I))
end program flipmeoff

并产生输出:

1.0 2.0 3.0
4.0 5.0 6.0
7.0 8.0 9.0

7.0 8.0 9.0
4.0 5.0 6.0
1.0 2.0 3.0

T T F
F T F
F F T

F F T
F T F
T T F

1 2 3
4 5 6
7 8 9

7 8 9
4 5 6
1 2 3

不幸的是,Fortran 不允许您像派生类型那样重命名内部类型。结果是可以与内部类型一起使用的模板文件必须使用implicit 类型。

【讨论】:

  • 不分配翻转?
  • 分配时分配。我不确定最近的版本是否允许这样做,我必须在我的代码中使用它以实现可移植性。太糟糕了,它对添加元素或类似元素没有帮助。
猜你喜欢
  • 2019-10-21
  • 1970-01-01
  • 2016-08-26
  • 1970-01-01
  • 2020-06-19
  • 1970-01-01
  • 2021-09-09
  • 2011-03-08
相关资源
最近更新 更多