如何在 Fortran 中支持 'same' 派生类型的多个版本?



>EDIT以提供更多细节:

1(提供库的代码不能(容易(更改,因此profile_v1_typeprofile_v2_type应该被认为是不可变的。

我已经实现了@francescalus建议,它适用于我的小型测试用例,但我认为我对这个问题不够清楚。原因是我只能修改我的代码,而不能修改来自库的代码/类型。问题在于,两者都会在导入的profile_type中t,这与父类型冲突。

但是,我将实现一些东西,其中我复制所需的派生类型的内容,然后使用指针和类型绑定过程指向要使用的profile_type版本的组件。它没有我想要的那么干净,但它比我现在好多了。


我支持一个与另一个具有 2 个版本的代码接口的代码 - 这两个版本在接口上非常相似,尽管输入和输出在属性上相同,但它们显然是不同的派生类型(它们来自不同的库,并且其中包含的变量略有不同。这些类型中的大多数变量名称都是相同的,但至关重要(。

(显然(有必要在运行时同时支持两者,否则我将在编译时预处理这一切。

目前,我已经懒惰地将每个版本(以及它使用的派生类型的所有版本(的相同代码复制并粘贴到单独的子例程(*_v1.f90,*_v2.f90(中。

这很烦人,而且不太易于维护。

我希望能够做的是使用某种不关心它所指向什么的指针(或者更确切地说,从它指向的内容中获取其类型信息,并且足够聪明,可以知道里面有什么(。

正如我上面所说,名称大多相同,例如(t,表示温度,例如(

从库的 v1

TYPE profile_v1_type
    REAL :: t
! loads of other stuff
END TYPE profile_v1_type

从库的 v2

TYPE profile_v2_type
    REAL :: t
! loads of other stuff, more than the first version
END TYPE profile_v2_type

在我的代码中:

TYPE profile_container_type
    TYPE(profile_v1_type) :: profile_v1
    TYPE(profile_v2_type) :: profile_v2
! other arrays that are common inputs to both
END TYPE
! It's actually USE'd then allocated and initialised elsewhere, but I hope you get the idea
!USE profile_container_mod, ONLY : profile_container
TYPE(profile_container_type), TARGET :: profile_container
TYPE(*) :: p
REAL :: t1
!Version determined by a namelist
IF (Version == 1) THEN
    p => profile_container % profile_v1
ELSE IF (Version == 2) THEN
    p => profile_container % profile_v2
ENDIF
t1 = p % t + 1
.
.
.

ifort 19 给出了以下(预期(错误:

test.f90(24): error #8776: An assumed type object must be a DUMMY argument.   [P]
TYPE(*), POINTER :: p
--------------------^
test.f90(24): error #8772: An assumed type object must not have the ALLOCATABLE, CODIMENSION, POINTER, INTENT(OUT) or VALUE attribute.   [P]
TYPE(*), POINTER :: p
--------------------^
test.f90(39): error #6460: This is not a field name that is defined in the encompassing structure.   [T]
t1 = p % t + 1
---------^
compilation aborted for test.f90 (code 1)
将 TYPE(*(

替换为 CLASS(*( 给出(仍然是预期的(:

test2.f90(39): error #6460: This is not a field name that is defined in the encompassing structure.   [T]
t1 = p % t + 1 ! or some clever function...
---------^
compilation aborted for test2.f90 (code 1)

这是通过选择您要处理的类型来解决的,但我的观点是我想对 v1 和 v2 代码做同样的事情(永远不会两者兼而有之(。我想做很多次,不是在这个例程中,而是在十几个例程中。

如果响应者能够提供一个简单的示例来遵循,我愿意使用 C 指针。我已经尝试(不是最近(使用 C 互操作性解决这个问题,但显然没有成功!

无限的多态实体在这里不是正确的方法。

相反,我们可以定义一个基本类型,其中包含所有通用数据和各种其他类型的处理。 在这里,我们将这个基本类型称为profile_base_type

type profile_base_type
  real t
end type

其他两个特定配置文件可以扩展此基础:

type, extends(profile_base_type) :: profile_v1_type
  ! v1 specific parts
end type
type, extends(profile_base_type) :: profile_v2_type
  ! v2 specific parts
end type

然后我们可以声明一个基类型的多态指针

class(profile_base_type), pointer :: p

可以指向任一扩展类型的目标:

p => profile_container%profile_v1
p => profile_container%profile_v2

现在,我们可以访问类型profile_base_type中的p组件

t1 = p%t + 1

无需使用选择类型构造。

当然,扩展类型的这些特定方面不能以这种方式访问,但还有其他注意事项。

最新更新