【问题标题】:Is it possible in Fortran to assign procedure name at run time in a type bound procedure?Fortran 中是否可以在运行时在类型绑定过程中分配过程名称?
【发布时间】:2023-01-18 23:56:30
【问题描述】:

我发现了类型绑定过程,并且想知道如何使用它们。我有按预期工作的代码:

module utils
implicit none
type TypeParam
  integer :: val
  contains
    procedure :: initval  => initI
    procedure :: writeval => writeI
end type TypeParam
contains
!---------------------------
  subroutine initI(this,val)
  class(TypeParam),intent(inout)::this
  integer,intent(in) :: val
  
  this%val=val

  end subroutine initI
!---------------------------  
  subroutine writeI(this)
  class(TypeParam),intent(inout)::this
  
  print*,this%val

  end subroutine writeI      
!---------------------------  
end module utils

program testtypebound
use utils
implicit none
type(TypeParam) :: TP(2)

call TP(1)%initval(3)
call TP(2)%initval(5)
call TP(1)%writeval() ! Returns 3
call TP(2)%writeval() ! Returns 5

end program testtypebound

现在我不知道如何在运行时分配 initval 和 writeval,如果它有任何意义的话。让它们指向 null() 并在主程序中将它们分配为 TP(1)%initval=>othersubroutine。

下面的代码不使用类型绑定过程,可以满足我的要求,但不确定是否可行。第二种方法有什么缺陷吗?

非常感谢

module utils
implicit none
type TypeParam
  integer :: val
  procedure(InitValInteger),  pointer :: initval  => null()
  procedure(WriteValInteger), pointer :: writeval => null()
end type TypeParam

interface
  subroutine InitValInteger(this,val)
  import TypeParam
  class(TypeParam),intent(inout)::this
  integer,intent(in) :: val
  end subroutine InitValInteger

  subroutine WriteValInteger(this)
  import TypeParam  
  class(TypeParam),intent(inout)::this  
  end subroutine WriteValInteger  
end interface

contains
!---------------------------
  subroutine initI(this,val)
  class(TypeParam),intent(inout)::this
  integer,intent(in) :: val
  
  this%val=val

  end subroutine initI
!---------------------------  
  subroutine writeI(this)
  class(TypeParam),intent(inout)::this
  
  print*,this%val

  end subroutine writeI      
!---------------------------  
end module utils

program testtypebound
use utils
implicit none
type(TypeParam) :: TP(2)

TP(1)%initval =>initI
TP(1)%writeval=>writeI
TP(2)%initval =>initI
TP(2)%writeval=>writeI
call TP(1)%initval(3) 
call TP(2)%initval(5)
call TP(1)%writeval() ! Returns 3
call TP(2)%writeval() ! Returns 5

end program testtypebound

澄清

正如 cmets 中指出的那样,前面的示例可能没有用。这是我认为可以做我想要的并且可以扩展到我的真实代码的代码:

module utils
implicit none
type TypeParam
  integer :: val
  procedure(UseValue),  pointer :: useval  => null()
end type TypeParam

interface
  real*8 function UseValue(this,i)
  import TypeParam
  class(TypeParam),intent(inout)::this
  integer,intent(in) :: i
  end function UseValue
end interface
contains
!---------------------------
  real*8 function useval1(this,i)
  class(TypeParam),intent(inout)::this
  integer,intent(in) :: i
  
  useval1=this%val+i

  end function useval1
!---------------------------
  real*8 function useval2(this,i)
  class(TypeParam),intent(inout)::this
  integer,intent(in) :: i
  
  useval2=this%val**2+i

  end function useval2         
!---------------------------  
end module utils

program testtypebound
use utils
implicit none
integer :: i
type(TypeParam) :: TP

write(*,*) "Enter version 1 or 2"
read(*,*) i

if(i==1)then
  TP%val=2
  TP%useval =>useval1
elseif(i==2)then  
  TP%val=1
  TP%useval =>useval2
else
  write(*,*) "Version unknown (1 or 2)"
  stop  
endif
print*, TP%useval(2) ! Returns 4 if i=1 and 3 if i=2

end program testtypebound

但在我开始实施之前,这段代码是否有缺点、缺陷?可以使用类型绑定过程使其更简单/更紧凑吗?在现实生活中,TP 将是一个数组,这样数组的每个组件将根据用户输入保存不同的过程。

【问题讨论】:

  • “现在我不知道如何在运行时分配 initval 和 writeval,如果有任何意义的话。”这取决于您要如何使用这些过程。在您展示的示例程序中,这样做意义不大,但在其他情况下却很有意义。你希望有多通用/灵活?
  • @fracescalus 谢谢。如果不发布另一个更长的示例,我不确定如何更好地解释。我希望能够根据用户输入选择指向一个或另一个子例程。子例程将具有相同的参数,但会做不同的事情。这些子例程将取决于不同的参数以及派生类型中托管的值。重点是避免在整个代码中使用条件语句,并为子例程使用通用名称。您认为代码 2 可以接受吗?
  • 好吧,你总是可以使用函数指针,就像你在上一个例子中所做的那样。但是函数指针与类型绑定过程不同。那么,你真正的问题是你最后在样本中做了什么吗?用函数指针的方案是否可行?这与您在帖子第一部分中显示的内容非常不同。

标签: pointers interface fortran


【解决方案1】:

类型绑定过程“绑定到派生类型并通过该类型的对象引用”(Fortran 2018,3.112.6)。被绑定到一个类型而不是目的意味着相同类型的两个对象产生相同的引用。 (此外,类型的定义在执行期间不能更改。)

过程指针组件不同:它是类型的组件,类型的每个对象实例都可以有自己的值,对于变量,其值可以在执行期间更改。

哪种机制最适合用例取决​​于需要什么。如果您希望相同类型的两个对象解析为不同的过程引用,或者希望引用的过程在执行过程中发生变化,您将使用过程指针组件。

过程指针可以是非关联的,并且类型绑定过程没有等效状态。这意味着您有责任确保 call a%s() 具有与目标关联的 s 过程指针组件指针,但也允许您执行类似 if (ASSOCIATED(a%s)) ... 的逻辑(如果它具有已定义的关联状态)。您还负责确保它始终指向您希望它指向的位置(另请注意,不能保护组件)并且为了方便起见,您最终可能会编写一个结构构造函数。

同样,过程指针组件可以以绑定名称不能使用的方式使用:call run(a%s) 允许用于过程指针组件,但不允许用于类型绑定过程。

也就是说,基于运行时条件的引用用例甚至可以使用类型绑定过程来解决:

type t
  logical :: use_a = .TRUE.
 contains
  procedure :: selector
end type t

selector 是一个像这样的包装器

subroutine selector(this, val)
  class(t), intent(in) :: this
  integer, intent(in) :: val

  if (this%use_a) then
    call A(this, val)
  else
    call B(this, val)
  end if
end subroutine selector

【讨论】:

    猜你喜欢
    • 2012-07-17
    • 1970-01-01
    • 2021-12-04
    • 2016-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    • 1970-01-01
    相关资源
    最近更新 更多