在 Fortran 数组中删除变量?



我有以下代码,具有抽象类型,继承类型和短程序,我在其中创建一个对象并将其存储在数组中。

module m
implicit none
type :: container
class(a), allocatable :: item
end type container
type, abstract :: a
integer, public :: num
end type a
type, extends(a) :: b
integer, public :: num2
end type b
end module m
program mwe
use m
implicit none
class(a), allocatable :: o1
class(container), allocatable :: arr(:)
o1 = b(1, 2)
allocate(arr(2))
arr(1) = container(o1)
select type(t => o1)
type is(b)
write(*,*) t%num, t%num2
end select
select type(t => arr(1)%item)
type is(b)
write(*,*) t%num, t%num2
end select
end program mwe

问题是,输出如下所示:

1           2
1           0

可以看出,存储在数组中的同一变量将第二个变量取消。为什么会这样?是因为数组的类型是a,它只包含第一个变量吗?

我正在使用ifort version 18.0.3编译代码。

我相信

arr(1) = container(o1)

无效的 Fortran 2008。 这是一个内在赋值语句,但标准的第 7.2.1.2 节说

内在赋值语句中,(1( 如果变量是多态的,它应该是可分配的,而不是协数组。

据我所知,arr(1)是多态的,但不可分配,因此符合标准的编译器应该发出错误并中止编译。

如果我的推理是正确的,那么英特尔 Fortran 编译器编译此代码的事实是一个编译器错误,应报告给英特尔。

与ripero的答案一样,可以说该程序的任何输出都是有效的。 但是,我们可以对代码进行简单的修改以使其正确 Fortran。1这个答案与这个修改后的版本有关。

我会调用此意外输出并寻求编译器供应商的帮助。

使用具有多态可分配组件的结构构造函数是 Fortran 中的新领域之一。 编译器可能需要一段时间才能赶上或正确完成。

我已经使用英特尔 Fortran 18.0.2 测试了您的代码,并看到了相同的输出。

对于您的问题

是因为数组的类型是a,它只包含第一个变量吗?

否:在具有输出tselect type部分中是类型为b的非多态实体。

您可以通过避免使用结构构造函数来解决此问题:

arr(1)%item = o1

我还看到 18.0.2 之前的英特尔编译器仍然做一些不同的事情。


1附声明

class(container), allocatable :: arr(:)

arr是多态和可分配的。 正如里佩罗所指出的,这意味着arr(1)arr的元素是多态的。 但是,作为数组元素,arr(1)本身不是多态的,因此可能不在内部赋值语句的左侧。 我们可以通过两种方式更改代码:提供定义的赋值,或者使arr非多态。 在问题的代码中,似乎没有理由让容器多态,所以我会考虑

type(container), allocatable :: arr(:)

此外,正如在对该问题的评论中所讨论的,如果您希望使用 gfortran 8 或更早版本来查看会发生什么,您还应该修改问题中的代码,以便派生类型的定义container位于派生类型的定义之后a

最新更新