【问题标题】:Procedure inheritance rules in Fortran 2003/2008 for class(*)Fortran 2003/2008 中类(*)的过程继承规则
【发布时间】:2014-02-23 11:41:23
【问题描述】:

考虑下面的代码

module classes
Type AData
end Type

Type A
contains
procedure :: Work
end type

Type, extends(AData) :: BData
end Type

Type, extends(A) :: B
contains
procedure :: Work => Work2
end type

contains

subroutine Work(this, D)
class(A) :: this
class(*) :: D
end subroutine

subroutine Work2(this, D)
class(B) :: this
class(BData) :: D
end subroutine

end module classes

这有效吗?它被 ifort 接受并被 gfortran 拒绝(因为 Work2 的第二个参数中的类不相同)。

如果它无效,它在某些情况下显然很有用:对于更多不同类型的参数,后代过程必须有多个嵌套的“选择类型”语句才能将参数转换为预期的类型。如果在编译时就知道子类中参数的类型(以丢失一些编译时一致性检查为代价),这将非常冗长并且可能效率也较低。是否有编译器选项可以让 gfortran 接受这个结构,还是应该是 gcc 错误报告/功能请求?

--编辑--: 明确地说,Gfortran 4.9 主干给出 错误:覆盖过程“work”在 (1) 的参数不匹配:参数“d”中的类型不匹配 (CLASS(bdata)/CLASS(*))

ifort(但不是 gfortran)也允许诸如

之类的结构
subroutine Work2(this, D)
class(B) :: this
class(*), target :: D
class(BData), pointer :: B

B=>D    

end subroutine

因此似乎将类(星号)变量视为具有来自开发人员的“相信我,我知道它是什么类型”标签。对我来说,这似乎非常合理(如果谨慎使用),并且避免了选择类型操作的开销,有时还避免了冗长的多个嵌套选择类型语句。我知道进行盲类型转换的唯一其他有效方法是通过一个外部子例程推动事物,其中根本没有对参数进行类型检查(在 f90 中绕过传递任意类型参数的 horrible 方法)。

使用其他类型覆盖类(星型)过程的愿望也出现在基本上下文中,例如您想要传入函数和任意对象的最小化库。在这里,即使最小化器不知道,开发人员和特定函数实现也总是知道对象是什么类型,因此您不希望在使用 class(*) 参数的函数实现中执行“选择类型” .

【问题讨论】:

  • 在您的代码上使用 gfortran 4.8.2 有人告诉我“错误:在 (1) 处覆盖过程 'work' 的参数不匹配:参数 'd' 中的类型/等级不匹配”这就是问题所在你是说?
  • 编辑问题以添加更多信息
  • 您关于允许的指针分配形式的附加信息与围绕过程特征匹配要求的原始问题并不真正相关。
  • class() 并不是你真正想要的“相信我”。 TS29113 是增强 C 互操作性的技术规范,增加了 TYPE() 和 DIMENSION(..) 以等效于 C 的 void *。虽然主要用于从 Fortran 调用到 C,但您可以使用这种方式声明带有参数的 Fortran 例程,但它通常需要 TRANSFER 才能将虚拟对象“强制转换”为已知类型。这是目前称为 Fortran 2015 的规范的一部分。

标签: fortran


【解决方案1】:

B 中的类型绑定过程覆盖 A 中的过程,并且 Fortran 2008 标准第 4.5.7.3 节有

重写和重写的类型绑定过程应满足以下条件。

  • ...

  • 按位置对应的伪参数应具有相同的名称和特征,但传递对象伪参数的类型除外。

我对此的理解是D 在两个子例程中必须是相同的类型。因此,最小的变化确实是至少在work2 中有一个select type 构造(可能在两个子例程中都有class(Adata) 作为声明)。

但是,以下是否可行?

module classes
  Type AData
  end Type AData

  Type A
   contains
     procedure :: work_adata
     generic :: Work => work_adata
  end type A

  Type, extends(AData) :: BData
  end Type BData

  Type, extends(A) :: B
   contains
     procedure :: work_bdata
     generic :: work => work_bdata
  end type B

contains

  subroutine Work_adata(this, D)
    class(A) :: this
    type(Adata) :: D
  end subroutine Work_adata

  subroutine Work_bdata(this, D)
    class(B) :: this
    type(BData) :: D
  end subroutine Work_bdata

end module classes

这解决了由数据类的多态性引起的困难,方法是使用虚拟对象的类型声明。

【讨论】:

  • 谢谢。通用方法是否适用于这样的典型用途: subroutine test(X, D) class(A) :: X class(AData) :: D call X%Work(D) end subroutine - 我想不幸的是不是?
  • 是的,如果你确实想充分利用多态性,那么select types 必须出现在某个地方,或者在testwork 中。通用方法只是另一种选择(您可以通过将test 本身设为通用来扩展...)。哪个更好取决于您的整体设计以及各种类型的相关性。
  • 确认:英特尔还表示,ifort 接受的两种形式都是编译器错误,并且已提出问题以供将来修复。
猜你喜欢
  • 2013-05-18
  • 2013-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多