在我正在从事的项目中,我发现自己经常需要在创建新对象和销毁旧对象时调整对象数组的大小。整个代码中许多不同的派生类型都会发生这种情况,其中大多数类型彼此没有关系。编写代码来调整这些数组的大小以获得唯一的派生类型是很乏味的,因此我想尝试使用无限的多态虚拟参数编写几个辅助子例程,以便任何派生类型数组都可以使用这些子例程。
我发现我的无限多态例程可以使用 CLASS(*),INTENT(INOUT)::val 进行编译和调用。这个虚拟参数将接受一个整数、一个可分配的整数或一个指向整数的指针。但是,一旦我尝试添加 ALLOCATABLE 或 POINTER 属性,子例程就会正确编译,但我无法在不出现编译器错误的情况下调用它。由于我的目标是能够调整派生类型数组的大小,因此这些属性对于例程能够解除分配/分配/关联值来说是必需的。
这里有一些测试代码,它们甚至没有尝试实际执行任何操作,但无法编译。此版本使用标量具体类型,但使用具体类型数组或派生类型数组的原始代码中会出现相同的错误
MODULE Resize_mod
PUBLIC
CONTAINS
SUBROUTINE resize(val)
CLASS(*),INTENT(INOUT) :: val
WRITE(*,*) 'resize'
ENDSUBROUTINE resize
SUBROUTINE resize_alloc(val)
CLASS(*),ALLOCATABLE,INTENT(INOUT) :: val
WRITE(*,*) 'resize_alloc'
ENDSUBROUTINE resize_alloc
SUBROUTINE resize_ptr(val)
CLASS(*),POINTER,INTENT(INOUT) :: val
WRITE(*,*) 'resize_ptr'
ENDSUBROUTINE resize_ptr
ENDMODULE Resize_mod
PROGRAM testResize
USE Resize_mod
INTEGER,TARGET :: array0d
INTEGER,ALLOCATABLE :: alloc0d
INTEGER,POINTER :: ptr0d
array0d=1
CALL resize(array0d)
ALLOCATE(alloc0d)
alloc0d=1
CALL resize(alloc0d)
!Following line gives: "Error: Actual argument to ‘val’ at (1) must be polymorphic"
CALL resize_alloc(alloc0d)
ALLOCATE(ptr0d)
ptr0d=1
CALL resize(ptr0d)
!Following line gives: "Error: Actual argument to ‘val’ at (1) must be polymorphic"
CALL resize_ptr(ptr0d)
ENDPROGRAM testResize
如图所示,代码产生以下错误:
testResize.f90:31:20:
CALL resize_alloc(alloc0d)
1
Error: Actual argument to ‘val’ at (1) must be polymorphic
testResize.f90:37:18:
CALL resize_ptr(ptr0d)
1
Error: Actual argument to ‘val’ at (1) must be polymorphic
如果我注释掉错误中指定的两行,我会得到以下正确的输出:
resize
resize
resize
我已经广泛编写了 Fortran 代码,但以前从未尝试过使用无限多态性。请让我知道我想做的事情是否可行,如果可以,请告诉我我做错了什么。
我使用的是 gfortran 编译器 5.4.0,据我所知,它应该完全支持无限多态性。
最佳答案
该错误消息只是语言规则限制的重述 - 请参阅 Fortran 2018 标准中的 15.5.2.5p2。该限制是为了阻止被调用的过程将可分配的虚拟参数重新分配到与实际参数不同的类型或种类(或者,对于指针虚拟参数,将虚拟参数与不同的类型或种类相关联)。这并不特定于无限多态参数 - 它适用于任何可分配或多态虚拟参数,在这种情况下,语言中的限制会阻止过程将虚拟参数分配到类型继承树的不同分支。
无限多态对象在运行时类型不可知的存储中发挥作用,但它们不适合一般情况下的泛型编程。
该语言以通用方式为常见数组操作提供了一些语法支持,但是当前的编译器可能无法有效地实现这些语法。例如,可以使用语法 array = [ array, element ]
将元素附加到可分配数组。
否则,您需要为数组操作提供特定于类型的过程。对于相同的操作,无论参数类型如何,每个过程体内的标记序列通常可以是相同的,在这种情况下,可以使用 INCLUDE 来减少重复源代码的数量。
改进对泛型编程的支持是该语言的下一个修订版正在考虑的一个方面。
关于pointers - 具有可分配或指针属性的无限多态虚拟参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56466785/