在Fortran 2003中键入绑定过程重载

Aar*_*ron 4 oop fortran gfortran fortran2003

我已经用Java编程了几年; 但是,我现在正在学习一门使用Fortran作为示例代码(77标准)的课程.虽然我一直认为Fortran是一种古老的语言,但我决定使用gfortran编译器试用2003标准的最新实现来看看它的优点.到目前为止,我对现代功能感到惊讶,但我遇到了一个问题,下面的例子证明了这个问题.

    module mod1
      type type1
        real :: x
        real :: y
        contains
        procedure :: compute
      end type type1
      contains
      subroutine compute(this)
        class(type1) :: this
        this%y = this%x*2 - 1
        write (*,*) this%x,this%y
      end subroutine
    end module mod1

    module mod2
      type type2
        real :: x
        real :: y
        contains
        procedure :: compute
      end type type2 
      contains
      subroutine compute(this)
        class(type2) :: this
        this%y = this%x - 5
        write (*,*) this%x,this%y
      end subroutine
    end module mod2

    program test
      use mod1
      use mod2
      implicit none
      type(type1) myType1
      type(type2) myType2
      myType1%x = 4
      myType2%x = 5
      call myType1%compute
      call myType2%compute
    end program test
Run Code Online (Sandbox Code Playgroud)

这会产生编译错误:"在(1)中参数'this'中输入不匹配;在引用call myType2%compute语句时将TYPE(type2)传递给CLASS(type1)" .

我的问题是范围.看来,通过该class(<class_name>) :: this语句,编译器应该能够将子例程绑定到特定的派生类型或其后代.从这里开始,编译器在概念上难以搜索在子例程中本地启动的变量定义,然后继续执行特定实例的祖先树this.这将消除所有明确的this%语句,这些语句往往会使我的类型绑定过程在几个语句之后难以阅读.例如,

    this%tempNew(xI) = this%lamda*this%temp(xI-1)+(1-2*this%lamda)*this%temp(xI)+this%lamda*this%temp(xI+1)
Run Code Online (Sandbox Code Playgroud)

似乎比读取/写入要少得多

    tempNew(xI) = lamda*temp(xI-1)+(1-2*lamda)*temp(xI)+lamda*temp(xI+1)
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,通过class(<class_name>) :: this语句相当明显,每个变量都应绑定.

另一个结果是,似乎两个单独的派生类型不能具有相同名称的绑定子例程(如错误消息所示).我已经看到了两种常见的方法.首先是显式调用每个子例程compute_type1compute_type2.访问这些子例程时,这在代码中看起来非常难看和冗余.例如call myType1%compute_type1.第二个选项(参见例如Fortold 2003中具有不同排名的重载fortran接口,类型绑定函数重载)似乎更好,是区分绑定名称和过程名称.例如,类型定义将包括procedure :: compute type => compute_type1.这解决了访问子例程时的问题,但是在开发具有许多实现相同绑定名称的派生类型的大型项目时,我会发现问题.我宁愿不必跟踪我所拥有的子程序名称,也没有在任何给定项目中使用过.这往往会使名称保持相当长的时间并且最终不易读取.

所以我的问题有3个组成部分:

  • 是否有this%<var_name>类型绑定过程中类成员的显式类型的更清晰的替代方法?
  • 有没有办法让编译器认识到应该根据class(<class_name>) :: this语句绑定一个过程?当前重载子程序/函数名称的方法似乎是90/95标准的工件,它不允许将这些绑定到类型.
  • 如果没有,是否有一些与此实现相关的性能提升?这两个问题似乎都可以在编译时解决,我很乐意为表达能力的提高而牺牲.

fra*_*lus 5

这更像是一个扩展注释,但由于编译器失败,您似乎被迫推测.我已经使用gfortran 4.8.3编译了代码而没有错误,并且具有预期的结果.而且,在我看来,你想要发生的事情应该发生.

另一个结果是,似乎两个单独的派生类型不能具有相同名称的绑定子例程(如错误消息所示).

虽然两个子例程都被调用,compute但它们是在单独的模块中,这是允许的,尽管你的use语句使得call compute(...)(你没有做的)模糊不清.如果类型定义在同一个模块中,那么你将不得不诉诸这个procedure :: compute => compute_typex技巧,但call mytype1%compute仍然可以接受.

我建议如果您compute通过类型绑定公开子例程,那么您可以private在模块中使用它们,或者至少不要明确use它们.[也就是说,有use mod1, only : type1.]

至于你是否坚持type%...在子程序中,那么是的,我认为你是.也就是说,根据Fortran 2008,有一个associate构造

subroutine compute(this)
  class(type1), intent(inout) :: this
  associate (x => this%x, y => this%y)
    ...
  end associate
end subroutine
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,这并没有增加太多.还有其他可怕的伎俩,我不会详细说明.

  • 您的偶然观察是因为您的代码缺少"隐式无",而不是因为您获得了所需的行为. (4认同)