将多态数组的子集复制到目标多态数组中

Copying subsets of polymorphic arrays into target polymorphic arrays

我在子例程中有两个派生类型多态数组(obj1 和 obj2)。基于子程序的使用,虽然两个数组的类型可能不同,但两个数组的类型相同;例如,A 型或B 型。在下面的示例代码中,我只展示了抽象class(模型)的一个子类型,而实际上,我希望它适用于多个子类型。此外,在生产代码中,model1 的元素在此副本之前已被修改。

program test

        use env_kindtypes,              only: si, dp

        use abs_obj_model,              only: model
        use obj_linearDivisionModel,    only: linearDivisionModel

        implicit none

        class(model),allocatable        :: model1(:), model2(:)

        allocate(linearDivisionModel::model1(10))

        !want e.g. model2 = model1([1,4,6,2])

        ![...]

给定obj1,obj2(类型A)(在示例代码中给定为model1,model2,类型为linearDivisionMode)和一组索引,我想将指定的元素从obj1转移到obj2,在此过程中分配obj2 .

我已经尝试了很多方法,但 none 似乎有效。

首先,我试过使用向量下标直接赋值;这失败了,抱怨还不支持直接分配可分配的多态数组。

indices = [ 1 , 2 ]
model2 = model1(indices)

结果:

         model2 = model1(indices)
        1
Error: Assignment to an allocatable polymorphic variable at (1) is not yet supported

其次,我尝试使用来源分配。如果我尝试使用数组切片表示法,它会起作用(但我的问题不能仅用这样的范围来表达)。如果我尝试对源数组进行矢量索引,它会编译,但在运行时我会收到 运行 内存不足的错误(考虑到系统这是不现实的)。

    allocate(model2,source=model1(indices))

运行时结果:

Operating system error: Cannot allocate memory
Memory allocation failed

Error termination. Backtrace:
#0  0x434471 in __obj_lineardivisionmodel_MOD___copy_obj_lineardivisionmodel_Lineardivisionmode
    at build/processed_src/obj_linear_model.f90:462
#1  0x436c75 in cg_charge_fit
    at build/processed_src/test.f90:37
#2  0x403019 in main
    at build/processed_src/test.f90:22

有效,但不足以满足我的目的。

allocate(model2,source=model1(1:2))

第三,我已经能够分配多态数组,希望能够手动传输子元素:但是,当我尝试这样做时,我收到了关于多态对象和内部赋值的投诉,我稍后会回过头来在这个 post.

indices = [ 1 , 2 ]
allocate(model2(size(indices)),source=model1(1))
do i=1,size(indices)
        model2(i) = model1(indices(i))
enddo

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

我已经尝试使用类型 select 语句来删除多态上下文,但错误仍然存​​在。

select type (POBJECT => model1)
      TYPE IS (linearDivisionModel)
             allocate(linearDivisionModel::model2(size(indices)))
             do i=1,size(indices)
                      model2(i) = POBJECT(indices(i))
             enddo
end select

结果:

model2(i) = model1(indices(i))
 1
Error: Nonallocatable variable must not be polymorphic in intrinsic assignment at (1) - check that there is a matching specific subroutine for '=' operator

作为解决方法,我希望使用一个中间指针对象,并从中获取分配源。由于 f2008 标准(此处强制执行),我无法将指针分配给向量索引数组。有趣的是,如果我创建一个指针、向量索引该指针,编译器会出现段错误,表明发生了一些奇怪的事情。

为了解决编译器对内部赋值的抱怨,我考虑过编写赋值例程;然而,这引起了一系列新的担忧:这两个例程继承自的父类型是抽象的,我似乎无法在 class 中指定通用 deferred 赋值运算符,导致复杂的父级 class 需要相当多的私有方法来复制,因为它没有指定私有变量。此外,subclasses A 和 B 之间的转换定义不明确。这似乎仍然是唯一剩下的出路,而且似乎很复杂。

如何有效传输指定的多态子数组?

我使用的是 gfortran 版本 6.1.1。

有了完整的 F2008 支持,这只是一个赋值语句。

在该编译器的约束下,您可能需要考虑嵌套的 SELECT TYPE 构造,这消除了赋值左侧和右侧的多态性。

module my_types
  implicit none

  type, abstract :: model
  end type

  type, extends(model) :: linearDivisionModel
    character :: comp
  end type linearDivisionModel
end module my_types

program p
  use my_types
  implicit none

  class(model),allocatable        :: model1(:), model2(:)
  integer, allocatable :: indicies(:)

  ! define model1.
  block
    type(linearDivisionModel), allocatable :: tmp(:)
    allocate(tmp(10))
    tmp%comp = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    call move_alloc(tmp, model1)
  end block

  indicies = [1, 2, 4, 6]

  ! allocate model2.
  allocate(model2(size(indicies)), mold=model1)

  ! define model2
  select type (model1)
  type is (linearDivisionModel)
    select type (model2)
    type is (linearDivisionModel)
      model2 = model1(indicies)
    end select
  end select

  ! display results.
  select type (model2)
  type is (linearDivisionModel)
    print *, model2%comp
  end select
end program p

以上似乎适用于当前的 gfortran trunk。